redis底层的数据类型

在这里插入图片描述

所有的的数据,在最底层要么是字符,要是数字,redis中的所有的key都是string类型的
string
在这里插入图片描述
在redis3.2之前,使用的上述结构,一个char数组,一个使用长度,一个还剩多长,但这样在string比较短时候,比较浪费空间。
zhi
这个数据结构我们称之为 简单动态字符串(simple dynamic string,SDS)。

在3.2之后改成了这样:
在string长度小于32的时候(图片右下角)使用sdshdr5,用一个8为位的flag存储类型(高三位)和长度(低五位)。在实际的应用中,这个类型没有没用上,因为他不能扩容,他会被转成成下面的数据结构存储。

在string长度小于 2的8次方-1 的时候,用一个8为位的flag存储类型(高三位)和 第五位不存储东西;再用一个8位的len存储长度;再用一个8位alloc存储申请的内存空间

在string长度小于 2的32次方-1 的时候,用一个8为位的flag存储类型(高三位)和 第五位不存储东西;再用一个32位的len存储长度;再用一个32位alloc存储申请的内存空间

以此类推直到64位。

数字的是时候(int)
redisObject最后的prt占8字节,当存入的时候会把我们的value,强转一下,如果可以那么就直接存在着。int 4 long8 folt4 double8 正好。bitmap也是直接存在这,最大空间为2的8*8次方

当字符串长度小于等于44,类型是embstr,为什么是44?
在这里插入图片描述
当小于等于44的时候能直接开辟一个连续的空间,也就是一个缓存行,正好将redisObject和sds正好存到这个缓存行行中。redisObject整个的空间是16字节,sds中除去数据部分还有4字节确定的空间,分别是char数组中最后的\0、len、alloc、flags,缓存行是64字节,64-16-4=44(字节)。

raw:字符串长度大于44。当对短字符串使用append的时候,直接变成embstr,因为涉及到了字符串的拼接,也就是扩容。

list
使用lpoprpush命令取数据,事务异常可以从备份list中,回滚

为什么没有直接使用一个双端链表,而是有用了一个ziplist呢?
因为对于每一个qiuicklistNode都有一个前后指针,每个node都有(双向指针16字节),多了就很浪费空间。ziplist是一个非常紧凑的数据结构,比较节省空间。

那为什么不直接用ziplist?又整除一个quicklist
ziplist是一个非常紧凑的数据类型,当数据量过大的时候,操作起来也比较麻烦。所以使用quicklist分开

ziplist
在这里插入图片描述
在这里插入图片描述
zlbytes:32bit,表示ziplist占用的字符总数。
zltail:32bit,表示ziplist表中最后一项entry在ziplist中的偏移字节数。通过zltail我们可以很方便的找到最后一项,从而可以在ziplist尾端快速的执行push或者pop操作。
zlen:16bit,表示ziplist中数据项entry的个数。
zlend:zuplist最后一个字节,是一个结束标记,值固定等于255
entry:表示真正存放数据的数据项,长度不定
prerawlen:前一个entry的数据长度
len:entry中数据长度
data:真实数据存储

quicklist
在这里插入图片描述
quicklist中有quicklistNode,quicklistNode中是ziplist。可以通过参数设置没有个ziplsit的大小,也可以设置quicklist的压缩,压缩之后,所需要的连续的内存空间就会变小,中间的压缩,两头的不压缩,因为list中,只关注头结点。空间换时间,解决大数据量下ziplist寻址慢的问题。

lsit是怎么实现阻塞的
在这里插入图片描述
redis本身就是一个全局的hash表,redisDb。在这个表中,会维护一个blocking_keys,这个的底层也是字典,会把阻塞的key和客户端连关联维护起来。

hash
在这里插入图片描述
在ziplist中一个entry中存储key,下一个entry存储value。使用ziplist存储的时候,这个set是有序的,顺序就是你加入的顺序。但使用dict(hashtable)存储的时候是无序的。

在这里插入图片描述
redisDb中dict(hashtable)中有两个数组(ht[2]), 平时只会用到一个,收缩扩容的时候会用到第二个,根据key,hash到对应的数组位置,数组里存的是dictEntry,dictEntry中存储的是key和val指针,val指向redisObject,在这里redisObject的类型是hash,dict(hashtable)的两个数据,dictEntry存储key和val指正,val指向真正的值redisObject,redisObject现在是int、embstr、raw。

set
在这里插入图片描述

元素是整形,并且数量少于阈值用intset存储,不满足条件的时候,使用value为null的dict(hashtable)存储。

在这里插入图片描述
contents数组中存储真正的int值。

zset
当数据量小于阈值的时候使用ziplist存储,v1 s1 v2 s2。
在这里插入图片描述
大于阈值使用跳表存储
在这里插入图片描述
zset
dict 字典,就像hash一样key,value的存
zskiplist 跳表

zskiplist
zskiplistNode 头尾指针
length 元素个数
level 有效层级

zskiplistNode
sds 元素
double 分数
zskiplistNode 回退指针
zskiplistLevel(有向前的指针) 层级数组
在这里插入图片描述
backward回退的指针,但没有向前的指针。向前的指针在zskiplistLevel中,是forward。
zset中,数据在dict中存一份,zsl存一份。zskiplist存储这头尾节点,和当前的有效层。当查找150的时候,访问头节点的zskiplistNode中level数组中的有效层2层,2层指向了120,120小于150,那么便利120的level数组,第一个指向了尾,再看下一个,下一个指向了200,200大于150,那么走200的回退指针,发现是100,100小于150,那么150不存在。

redis本身就是一个全局哈希表,单机的redis有16的db,每个db都有一个redisDb哈希表
在这里插入图片描述


版权声明:本文为m0_37987402原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。