redis类型
String字符串 Int 简单动态字符串 sds
Redis的string自己构建了简单动态字符串,sds
Sds内部又可以转为int,embstr,raw
set a 1
type a
object encoding a
set b acd
type b
object encoding b
embstr 和 raw不同在于
embstr分配了一块连续内存存储 raw则没有
所以embstr请求一次内存就能得到 raw需要请求2次内存
SDS设计的好处:
struct sdshdr{
unsigned int len; //buf中已经使用的长度
unsigned int free;//buf中未使用的长度
char buf[];//柔性数据buf
};
效率 sds单独存储len长度,不会像c通过遍历字符串获取
防止数据溢出 c是没有字符串长度的,相邻的两个字符串的存储有可能是紧挨着的,当一个字符串变长时就没有办法放下,只能侵占后一个字符串的空间。前一个字符串的改变会影响后面字符串的改变。sds设计会先判断len是否满足,不满足会先扩展在进行修改
空间预分配 不仅分配必要的空间还好分配额外的空间,下次修改时会先判断未使用的空间是否够用,满足直接添加,不满足再进行扩充。可以减少内存分配的次数【额外分配未使用空间原则,当字符串修改后len的值小于1M会分配同样大小的未使用空间,如果大于1M会分配1M空间】
惰性空间释放 当字符串缩短后,并不会立即回收空间,而是放在预分配空间中。减少数据内存分配次数
后期因为小字符串会浪费内存,从而进行了改善,通过字符串长度进行sdshdr5,sdshdr8,sdshdr16,sdshdr32类型选择。sds.h文件中 sds.c文件
sdshdr5 很少使用,无法扩容
sdshdr8 正常使用
Hash哈希 Ziplist hashtable
Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。
Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
Redis的hash的底层是一个dict,当数据量比较小或者数据值比较小时采用Ziplist(界限可以通过config中的值进行修改)
设置一个hash表,hgetall获取在哈希表中指定 key 的所有字段和值
因为时ziplist压缩列表所以出来的值是顺序的
当一个值太大时,底层存储类型变成hashtable,hashtable是无序的,所以获取出来也是无序的
ziplist数据结构:
zlbytes:32位无符号整型,表示整个ziplist所占的空间大小,包含了zlbytes所占的4个字节。这个字段可以再重置整个ziplist大小时不需要遍历整个list来确定大小,空间换时间。
zltail:32位无符号整型,表示整个list中最后一项所在的偏移量,方便再尾部做pop操作
zllen:16位,表示ziplist中所存储的entry数量,也可以看作是长度
entry:不定长,可能又多个
zlend:8位,ziplist的末尾表示,值固定时255
entry的结构:【前一个entry的大小,当前编码类型和长度,真实的字符串和数字】
ziplist
优点:因为是连续的内存空间,所以利用率高,访问效率高
缺点:更新效率低 当插入或删除一个数据的时候,会频繁的扩展或缩小,然后进行数据的搬移。
List列表 Ziplist quicklist 双向循环链表
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
Redis的list有序的数据结构,底层分为ziplist和quicklist
quicklist: 双向循环链表
优点:更新效率高
缺点:增加了内存开销
quicklist 结构,其实是由ziplist组成的双向链表 源码在quicklist.h
Set集合 intset hashtable
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
集合对象的编码可以是 intset 或者 hashtable。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
Redis的set是无序的,自动去重的数据类型,它的底层是一个字典dict。当数据可以用整型并且数据元素小于配置文件中set-max-intset-entries是用intset,否则用dict
Zset有序集合 Ziplist skiplist 跳表
Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
Redis的zset是有序的,自动去重的数据类型。底层是由字典dict和跳表skiplist实现的,让数据较少时用ziplist来存储
ziplist可以在配置文件【redis.conf】中通过zset-max-ziplist-entries和zset-max-ziplist-value来配置,使用ziplist
最开始数据量少,选择的压缩列表的数据结构
当所保存的元素超过了zset-max-ziplist-entries对应的值(默认128)转换为跳表;
当添加元素的member的长度大于zset-max-ziplist-value对应的值(默认64)转换为跳表
skiplist跳表 源码server.h文件中
跳表是在列表的技术上增加了多重的索引,来提升查询的效率,以空间换时间,索引是需要占用空间的
通过数据结构的对比,压缩列表在有序性上的性能损耗相对较大,插入数据需要将数据后移;
跳表对数据的插入相对比较友好,可以直接修改指针;
跳表需要注意多级索引的退化,需要在合适的时机修改或重构索引;