【源码-6】redis的数据结构及编码

涉及到大佬文章的链接在此

https://blog.csdn.net/csdnlijingran/article/details/89116126
https://www.jianshu.com/p/c2841d65df4c

redis是一个kye value存储的内存数据库,key永远为string,value可能是redis对象中的任意一种。
redis可以保存的数据类型为String、List、Set、Hash、SortedSet。
redis值的数据结构会标识编码、类型、引用计数、指向底层数据结构的指针、最后一次被访问的时间。

typedef struct redisObject {
    
    
    //类型
     unsigned type:4;
     //编码
     unsigned encoding:4;
     //指向底层数据结构的指针
     void *ptr;
     //引用计数
     int refcount;
     //记录最后一次被程序访问的时间
     unsigned lru:22;
} robj;

存入key-value键值对时并不会指定对象的encoding,而是Redis会根据不统的使用场景来为一个对象设置不同的编码,可以达到节约内存、加快访问速度等目的。压缩列表的优势是集中存储,节省空间。

  • List的底层实现:

List的底层实现为双端链表(linkedlist)和压缩列表(ziplist),压缩列表的对象可以存储多个值,而双端链表对象是一个链表,可以在列表头和尾添加结点,只有当列表元素小于512个,且每个元素长度小于64字节的时候,使用压缩列表,其他时候,使用双端链表。这两个数值在redis.conf里面设置。

  • Hash的底层实现:

值是键值对的集合,实现可以是压缩列表(ziplist)和hashtable,ziplist的底层的第一个节点存放key,第二个节点存放value,hashtable的底层数据结构为字典数据结构。

  • Set的底层实现:

集合对象 set 是 string 类型(整数也会转换成string类型进行存储)的无序集合。键是一个字符串对象,值全部设为null。

  • SortedSet的底层实现:

底层基于压缩表(ziplist)和skiplist实现。为每个元素设置一个score作为排序依据。

  • 压缩表中每个元素紧紧挨在一起,第一个放元素,第二个放score。依据score排序,大的放后面,小的放前面。
  • skiplist使用zset结构作为底层实现。zset包含一个字典和一个跳跃表。字典的键保存元素的值,字典的值保存元素的分值。跳跃表结点的object属性保存元素的成员,score属性保存元素的分值。通过指针共享元素的成员和分值。
typedef struct zset{
    
    
     //跳跃表
     zskiplist *zsl;
     //字典
     dict *dice;
} zset;

跳跃表优点是有序,但是查询分值复杂度为O(logn);字典查询分值复杂度为O(1) ,但是无序,所以结合连个结构的有点进行实现。
虽然采用两个结构但是集合的元素成员和分值是共享的,两种结构通过指针指向同一地址,不会浪费内存。

  1. 跳跃表:

如果有n个元素,因为是2分,所以层数就应该是log n层 (本文所有log都是以2为底),再加上自身的1层。
查询复杂度为logn。

  1. 压缩列表的优点:

(1)节约内存,减少内存开销,Redis是内存型数据库,所以一定情况下减少内存开销是非常有必要的。
(2)减少内存碎片,压缩列表的内存块是连续的,并分配内存的次数一次即可。
(3)压缩列表的新增、删除、查找操作的平均时间复杂度是O(N),在N再一定的范围内,这个时间几乎是可以忽略的,并且N的上限值是可以配置的。
(4)四种数据对象都有两种编码结构,灵活性增加。

猜你喜欢

转载自blog.csdn.net/u010659877/article/details/105841974