Redis底层数据结构总结

Redis用于存储的存储格式分为5种对象:String对象、List对象、HashTable对象、Set对象和SortedSet。


  1. String字符串,用于保存字符串对象,同时可以作为缓冲区(AOF缓存区)
sdshdr{
int length;
int free;
char[] buffer;
}
  • C字符串和SDS之间区别

C字符串
SDS
获取字符串长度的复杂度为O(N)

O(1)
API不安全,可能造成缓冲区溢出
API安全,不会造成缓冲区溢出
修改字符串长度N次必然执行N次内存重新分配
最多执行N次内存重分配,大部分情况不需要
二进制不安全(之只能保存文本数据,中间不能包含空字符)
二进制安全,可以保存文本或者二进制数据
可以使用所有<string.h>库函数
使用部分库函数,字符串结尾同样以’\0’结尾,为了和C字符串部分兼容,可以使用部分库函数考虑


链表,用于链表键,慢查询、监视器、保存多个客户端状态,列表键包含较多元素或者包含的元素是较长的字符串时,会使用链表
  • 双端
  • 无环
  • 带头指针和尾指针
  • 带链表长度计数器
  • 多态(*Void不同各类型的值)


字典,用于数据库与哈希键。Redis中的字典使用哈希表作为底层实现,Redis里的字典包含2个HashTable,H[0]用于日常用的hash,而H[1]则是重哈希的时候使用
哈希表使用链地址方法来解决键冲突的问题,被分配到同一个索引上的多个键会连接成一个单向链表
渐进式Hash



跳跃表SkipList
有序,每个节点维护多个执行其他节点的指针,从而达到快速访问节点的目的,平均O(logN),最坏O(N)复杂度查找,同时通过顺序性操作来批量处理节点
     大部分情况可以和平衡树效率相当,然后跳跃表实现更加简单

SkipList

header
tail
level
length
同时,SkipList包含表头结点

SkipListNode{
     //层
     struct zskiplistLevel{
          //前进指针
          struct zskiplistNode * forward;
          //跨度,用于记录里两个节点之间的距离
          int span;
     }level[];
     //后退指针
     struct zskiplistNode *backword;
     //分值
     //double score
     //成员对象
     robj *obj;
}zskiplistNode;

每个跳跃表节点的层高都是1-32之间的随机数
同一个跳跃表中,多个节点可以包含相同的分值,但是每一个节点的成员obj必须是唯一的
跳跃表的节点按照分值大小进行排序,当分值相同时,节点按照成员的大小进行排序



整数集合
     当一个集合中只包含整数型元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现
有序的
struct intset{
     //编码方式
     uint32_t encoding;
     //集合包含的元素
     uint32_t length;
     //保存元素的数组
     int8_t contents[];
}
  1. 整数集合是集合键的底层实现之一
  2. 整数集合的底层实现为数组,这个数组以有序、无重复的方式保存着集合,在有需要时,程序会根据增加的元素的类型,改变这个数组的类型
  3. 编码的升级操作,给整数集合带来了操作上的灵活性,并且尽可能地节约内存空间
  4. 整数集合只支持升级操作,不支持降级


压缩列表(ZipList),用于当列表键只包含少量列表项,并且每个列表项要么是小整数值或者是长度较小的字符串
  1. 是一种为了节约内存空间而开发的特殊编码的顺序型数据结构(连续但不有序)
  2. 用于列表键或者哈希键的底层实现之一
  3. 可以包含多个节点,诶个节点可以保存一个字节数组或者整数型
  4. 新添加节点到列表件,或者从列表键中删除节点,可能会引发连锁更新的问题,但是这种操作出现的几率并不高
ZipList
zlbytes
(占用字节数)
zltail
记录表尾节点距离起始节点的offset
zllen
节点数
entry1
...
entryN
zlend
(末端标志)

ZipListNode
previous_entry_length
前驱节点的长度(1或者5字节)
encoding
content属性保存的类型信息
content

插入到指定节点之后,平均O(N),最坏O(N^2),最坏的情况是产生连锁更新,需要进行N次重分配操作,而每次空间从分配的最坏是O(N),故O(N^2).



对象,Redis中都是以对象的形式存在
RedisObject{
     unsigned type:4 //五种redis对象
     unsigned encoding:4//根据不同的编码,选择不同的底层实现
     void *ptr;//指向底层实现的数据结构的指针
}
  • 不同类型对应的编码对象
类型
编码
对象
Redis_String
Redis_Encoding_Int
整数型字符串
Redis_String
Redis_Encoding_Embstr

Redis_String
Redis_Encoding_Raw

Redis_List
Redis_Encoding_ZipList

Redis_List
Redis_Encoding_LinkedList

Redis_Hash
Redis_Encoding_Ziplist

Redis_Hash
Redis_Encoding_Hashtable

Redis_Set
Redis_Encoding_Intset

Redis_Set
Redis_Encoding_Hashtable

Redis_ZSet
1、Redis_Encoding_ZipList
2、Redis_Encoding_SkipList+字典实现
为啥要跳跃表+字段一起实现?效率考虑,跳越表范围查询特性保留
而字典:根据成员查找分值O(l)
     通过encoding属性来设置对象所使用的编码,而不是为特定的类型关联一种固定的编码,极大提升了Redis的灵活性和效率,针对不同的场景做优化。

String对象
embstr:保存短字符串的一种优化编码方式,调用一次内存分配函数来连续分配redisObject和sdshdr,同时释放内存也只需要一次,同时能够利用字符串所有数据保存在同一块连续的内存里,更好地利用缓存。



Redis每一个键和值都是一个对象
Redis采用引用计数的方式实现内存垃圾回收,当一个对象不在使用时,对象就会被自动回收
Redis的共享值0-9999字符串
对象会记录自己最后一次被访问的时间,用于计算对象的空转时间
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis是一个开源的内存数据库,它使用了多种数据结构来存储不同类型的数据。下面是几种常见的Redis底层数据结构的详解: 1. 字符串(String):字符串是Redis中最基本的数据结构。它可以存储任意类型的数据,包括数字、文本等。字符串在Redis中以字节数组的形式存储,可以通过键访问和修改。 2. 列表(List):列表是一个有序的字符串集合,可以在列表的两端进行插入、删除和获取操作。Redis使用双向链表来实现列表数据结构,它支持快速插入和删除操作。 3. 哈希(Hash):哈希是一种键值对的集合。在Redis中,哈希可以存储多个字段和对应的值,类似于关联数组或者字典。哈希在内部使用哈希表来实现,可以快速查找和修改字段值。 4. 集合(Set):集合是一组唯一且无序的字符串集合。Redis使用哈希表来实现集合数据结构,它支持添加、删除和判断元素是否存在等操作。 5. 有序集合(Sorted Set):有序集合是一组唯一且有序的字符串集合。在Redis中,每个元素都会关联一个分数,通过分数可以对元素进行排序。有序集合的实现使用了跳跃表和哈希表两种数据结构,它支持添加、删除、修改和范围查询等操作。 这些数据结构底层实现都是高效的,并且支持丰富的操作。Redis数据结构灵活性较高,能够满足不同类型的数据存储需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值