redis 5种数据结构底层实现

引言

redis底层c语言结构体(类似于java类)

1、redisServer结构体(表示redis服务器)

redis服务器中包含多个DB,默认是16个。我们主要关注成员变量redisDb

2、redisDB结构体(表示一个DB数据库)

注释:

  • dict表示字典。
  • expires 设置了超时的键超时
  • id 数据库ID

其他的成员变量就跳过了,主要关注成员变量dict,非常重要,因为所有的数据都是通过字典索引的

3、dict结构体(表示一个字典)

4、dictht结构体(hashtable)

字典的底层结构是hashtable实现的,所以要有dicEntry结构体

以O(1)的时间复杂度获取size长度

used代表当前数组里面用掉的长度

5、dictEntry结构体

dictEntry存放到hashtable中时如果产生hash冲突,所以就会用链表连接,next表示下一节点的dicEntry。

key和val都是redisObject结构体。

6、redisObject结构体

  • type表示真实数据的数据类型(string、list……)(对外的)(可以方便的确定执行的命令是否合法,例如只有string才能使用setnx命令)
  • encoding是redis底层关于真实数据的编码,很重要!对于内存的利用率有极致的追求
  • lru和内存淘汰策略有关
  • refcount和内存管理有关,用计数器法对是否存活的判断
  • ptr指针指向了数据的真实存储位置:String、hash、list、set、Sorted Set

上面几步总的流程图:

一、字符串String

redis数据存储时没有直接使用c语言的char[]来存储,c语言数据的结尾需要用‘\0’表示

3.2以前是可以动态扩容的数据结构

len表示数据长度。就不需要依赖于\0结尾了

缺点:如果我存储很短的字符串例如1,也会占用很多内存(len+free指针的内存占用空间,比数据本身还要大)

在3.2之后新增了一些数据结构,根据存储数据的长度判断,选择合适的结构,节省空间

注意:SDS_TYPE_5结构虽然有这一种,但是没有用(因为free字段没办法扩容),会自动转换成SDS_TYPE_8

底层两种编码结构

embstr和raw

如果存入字符串的长度小于43(最后还有一个\0结尾标识),则直接紧挨着redisObject对象分配在一个cpu缓存行中。一次就可以全部读取出来,不需要再通过ptr指针去拿(额外的寻址)。此时就为embstr编码类型,如图:

二、list

一个有序(按加入的时序排序)的数据结构,采用quicklist(双端链表)ziplist作为List的底层实现。

quicklist是由ziplist组成的双向链表

#通过设置每个ziplist的最大容量,quicklist的数据压缩范围,提升数据存取效率
# -5: max size: 64 Kb  <-- not recommended for normal workloads
# -4: max size: 32 Kb  <-- not recommended
# -3: max size: 16 Kb  <-- probably not recommended
# -2: max size: 8 Kb   <-- good
# -1: max size: 4 Kb   <-- good
list-max-ziplist-size -2
list-compress-depth 0

三、哈希hash

底层实现是一个字典(dict),也是redisDb用来存储K-V的数据结构。

当数据量比较小或单个元素比较小时,底层用ziplist存储。

#数据大小和元素阈值redis.conf设置
hash-max-ziplist-entries 512
hash-max-ziplist-value 64

执行命令设置一个hash值,可以看到所有元素是按照保存时的顺序

当我再给hash添加值时,发现顺序变乱,说明换了存储结构(由ziplist换为hash)ziplist是有序的,hash是无序的

ziplist(有序)存储结构如下: 

四、set 集合

底层使用instset和hashtable两种数据结构存储。inset可以理解为数组,hashtable是普通的哈希表

#inset集合最多包含多少个节点
set-max-intset-entries 512

添加元素时:

  • 如果存入的元素能够转换成int对象,则使用intset结构。否则使用hashtable。
  • 如果存入元素后intset长度超过512,则转换为hashtable。
  • 如果已经是hashtable结构了,则继续使用hashtable

五、zset集合

底层使用ziplist或skiplist(跳表)

满足以下配置时使用ziplist,否则使用skiplist

#元素数量小于128个
#所有元素的长度小于64字节
zset-max-ziplist-entries 128
zset-max-ziplist-value 64

ziplist结构: 

skiplist结构:

猜你喜欢

转载自blog.csdn.net/sumengnan/article/details/113090963