一文带你了解Redis底层五种基本数据类型的底层

看这篇文章之前建议您先看这一篇!!

我们长话短说,本文会带您了解redis的五种基本类型底层的数据结构以及如何实现。

RedisObject

redis中任意类型的 key 和 value 都会被封装成一个RedisObject ,这哥们也叫作redis对象,

  1. 什么是redisObject:从redis使用者的角度来说,一个redis节点在非集群的情况下包含十六个库。redis是一个k-v型数据库,库内对于k-v的映射使用一个dict来维护的。 key很好说了,是一个sds,value就比较多变了,为了在一个dict内能够存储不同类型的value,就需要RedisObject这种通用的数据结构。在这里插入图片描述
  2. redis会根据存储的数据类型不同,选择不同的编码方式。包含11种类型。
编号编码方式说明
0OBJ_ENCODING_RAWraw编码动态字符串
1OBJ_ENCODING_INTlong类型的整数的字符串
2OBJ_ENCODING_HThash表(字典dict)
3OBJ_ENCODING_ZIPMAP已废弃
4OBJ_ENCODING_LINKEDLIST双端链表
5OBJ_ENCODING_ZIPLIST压缩列表
6OBJ_ENCODING_INTSET整数集合
7OBJ_ENCODING_SKIPLIST跳表
8OBJ_ENCODING_EMBSTRembstr的动态字符串
9OBJ_ENCODING_QUICKLIST快速列表
10OBJ_ENCODING_STREAMStream流

五种数据结构

Redis中会根据存储的数据类型不同,选择不同的编码方式。每种数据类型的使用的编码方式如下:

数据类型编码方式
OBJ_STRINGint、embstr、raw
OBJ_LISTLinkedList和ZipList(3.2以前)、QuickList(3.2以后)
OBJ_SETintset、HT
OBJ_ZSETZipList、HT、SkipList
OBJ_HASHZipList、HT

String

根据上文可知,String这种数据类型有三种编码方式, 分别是, int,embstr , raw。 基本的编码方式是Raw,基于sds实现。 小于44字节就会用embstr,此时redisobject和sds是一片连续的空间,redis底层直接做了redisObject 的内存空间 的下一位就是sds。他俩紧挨着的。如果存的字符串是整数值,并且大小在LONG_MAX的范围内,采用int编码。数据直接保存在redisObject的指向实际保存数据空间的指针的位置上(8字节)。不需要SDS。在这里插入图片描述
图中的5只是redis用来测试的,实际上用不到。

在这里插入图片描述
总结:

String在redis里面确切的说使用一个redisObject表示的。Redisobject可能有三种编码格式,raw , embstr , int 。前两种用sds存储数据,int类型存放在指针位置,存long类型。

在对string进行incr,decr操作的时候,如果内部是int编码,可以直接进行加减操作。如果内部是另外俩哥们,redis试图把sds存储的字符串转换成long类型。如果能转成功,在进行加减操作。对一个内部表示long类型的string执行append,setbit,setrange这些命令,针对的还是string的值。而不是对long进行操作。这些操作会先把龙转成字符串操作。

List

Redis的List类型可以从首、尾操作列表中的元素

3.2版本之后,redis采用quickList作为list的数据结构。quickList是一种双向链表 + ziplist的数据结构。ziplist是链表的节点。

Set

Set是Redis中的单列集合,满足下列特点:

  • 不保证有序性
  • 保证元素唯一
  • 求交集、并集、差集

redis采用dict存储元素,key存储元素,value统一为nil。

存储的数据都是整数,并且元素数量不超过set-max-intset-entrys,set采用intset编码,节省内存空间。在这里插入图片描述
在这里插入图片描述

ZSET(important)

zet每一个元素都需要制定一个score和member。

  • 可以根据score值排序
  • member必须唯一
  • 可以根据member查询分数
    在这里插入图片描述

redis采用跳表加dict实现zset。因为跳表可以排序,同时存储score和member,但是跳表不能通过ele去找到对应的分数。而dict可以根据key找到value。所以redis结合二者。存两份数据,skipList里面一份,dict里面一份。这样查找排序效率非常高。就是比较耗内存。所以zset还会采用ziplist节省内存。 使用ziplist的条件(标准情况下):

  • 元素数量小于128
  • 每个元素小于64字节。

ziplist没有排序功能,需要编码实现。

  • score和ele是紧挨在一起的两个entry。
  • element在前,score在后,按照score升序排列。在这里插入图片描述

Hash

Hash结构与Redis中的Zset非常类似:

  • 都是键值存储
  • 都需求根据键获取值
  • 键必须唯一

区别如下:

  • zset的键是member,值是score;hash的键和值都是任意值
  • zset要根据score排序;hash则无需排序

底层实现方式:

  • ziplist或者dict,hash数据比较少的情况下,hash底层采用压缩列表进行存储。数据到达一定程度的时候会被转成dict。转换的原因就是ziplist很大的时候会有如下的缺点:
    • 每次插入或修改产生的realloc可能会造成内存拷贝,降低性能
    • 一旦发生内存拷贝,内存拷贝的成本也要增加,因为要拷贝更大的一块数据
    • ziplist数据项过多的时候,在他上面查找指定的数据项就会使性能变得低,因为ziplist查找需要遍历。

Hash结构默认采用ZipList编码,用以节省内存。 ZipList中相邻的两个entry 分别保存field和value(相对于zset,无非就是去了一个跳表,别的差不多)
当数据量较大时,Hash结构会转为HT编码,也就是Dict,触发条件有两个:

  • ZipList中的元素数量超过了hash-max-ziplist-entries(默认512)
  • ZipList中的任意entry大小超过了hash-max-ziplist-value(默认64字节)
    在这里插入图片描述
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值