1、String
1、实现方式:
1、RAW编码方式:默认的,redisObject指针指向SDS
2、EMBSTR编码方式:redisObject和SDS形成数组
3、INT编码方式:直接用redisObject指针存储,指针是无符号的8位
String是Redis中最常见的数据存储类型:
1、下图是RAW编码方式:
2、下图是EMBSTR编码方式
如果存储的SDS长度小于44字节,则会采用EMBSTR编码,此时object head与SDS是一段连续空间。申请内存时只需要调用一次内存分配函数,效率更高。
3、下图是INT编码方式
如果存储的字符串是整数值,并且大小在LONG_MAX范围内,则会采用INT编码:直接将数据保存在RedisObject的ptr指针位置(刚好8字节),不再需要SDS了。
总结:
可以看到String具有的三种转换形式
测试
2、List
2、实现方式:
1、3.2版本之前,ZipList和LinkedList来实现List
2、3.2版本之后,QuickList实现
Redis的List类型可以从首、尾操作列表中的元素:
哪一个数据结构能满足上述特征?
Redis的List结构类似一个双端链表,可以从首、尾操作列表中的元素:
在3.2版本之前,Redis采用ZipList和LinkedList来实现List,当元素数量小于512并且元素大小小于64字节时采用ZipList编码,超过则采用LinkedList编码
在3.2版本之后,Redis统一采用QuickList来实现List:
3、Set
3、实现方式:
1、Dict实现,value都存储null
2、如果都是整数,那么用Inset结构
Set是Redis中的单列集合,满足下列特点:
可以看出,Set对查询元素的效率要求非常高,思考一下,什么样的数据结构可以满足?
展示
4、ZSet
4、实现方式:
1、SkipList(有序)和HT(键值查找)结合构成
2、ZipList,两个entry构成一个,ele为键,score为值
ZSet也就是SortedSet,其中每一个元素都需要指定一个score值和member值:
1、可以根据score值排序
2、member必须唯一
3、可以根据member查询分数
因此,zset底层数据结构必须满足键值存储、键必须唯一、可排序这几个需求。之前学习的哪种编码结构可以满足?
源码分析
当元素数量不多时,HT和SkipList的优势不明显,而且更耗内存。因此zset还会采用ZipList结构来节省内存,不过需要同时满足两个条件:
①元素数量小于zset_max_ziplist_entries,默认值128
②每个元素都小于zset_max_ziplist_value字节,默认值64
ziplist本身没有排序功能,而且没有键值对的概念,因此需要有zset通过编码实现:
1、ZipList是连续内存,因此score和element是紧挨在一起的两个entry, element在前,score在后2、score越小越接近队首,score越大越接近队尾,按照score值升序排列
从下面代码可以看到
1、zset实现的两种方式
2、下面的是添加Zset的方法
5、Hash
5、实现方式:
本质和zset是一样的
1、直接用dict实现,去除跳表
2、使用ZipList实现
Hash结构与Redis中的Zset非常类似:
区别如下:
1、zset的键是member,值是score;hash的键和值都是任意值
2、zset要根据score排序;hash则无需排序
因此,Hash底层采用的编码与Zset也基本一致,只需要把排序有关的SkipList去掉即可:
因此,Hash底层采用的编码与Zset也基本一致,只需要把排序有关的SkipList去掉即可:
1、Hash结构默认采用ZipList编码,用以节省内存。 ZipList中相邻的两个entry 分别保存field和value
2、当数据量较大时,Hash结构会转为HT编码,也就是Dict,触发条件有两个:
①ZipList中的元素数量超过了hash-max-ziplist-entries(默认512)
②ZipList中的任意entry大小超过了hash-max-ziplist-value(默认64字节)
hash对应的两种结构
源码展示