引言
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结构: