首页 > 编程知识 正文

redis有序集合底层实现,redis数据结构底层实现

时间:2023-05-05 03:16:43 阅读:128995 作者:1970

摘自:https://zhuanlan.zhihu.com/p/102422311

仅做个人备份,浏览请看原文

快速列表快速列表是由zip列表组成的双向链表。 每个节点都使用ziplist存储数据。 本质上,快速列表中保存着一个个小zip列表。

结构

源码

typedefstructquicklistnode { structquicklistnode * prev; //上一个节点结构快速列表下一个; //下一个节点无符号char * ZL; //在保存的数据压缩之前的ziplist压缩之后压缩的数据unsigned int sz;/* ziplistsizeinbytes */unsigned int count :16;/* countofitemsinziplist */unsignedintencoding :2;/* raw==1ORL ZF==2*/unsignedintcontainer :2;/* none==1orz iplist==2*/unsignedintrecompress 33601;/* wasthisnodepreviouscompressed? */unsignedintattempted _ compress :1;/*节点can ' t compress; too small */unsignedintextra :10;/* morebitstostealforfutureusage */}快速列表节点; quickList是标准的双向链表放置,有头和tail,每个节点都是quicklistNode,包含一个prev和下一个指针。 每个quicklistNode都包含一个ziplist,其键值存储在*zp压缩链表中。 因此,quicklist封装ziplist一次,并使用较小的ziplist,以确保内存使用量和性能。为什么不全部使用ziplist呢?

: ziplist存储在连续的内存中,因此存储效率很高。 但不利于修改操作,插入和删除操作需要频繁申请和释放内存。 如果ziplist的长度特别长,则一次realloc可能会导致大量数据复制。

ziplist压缩列表ziplist是为了节约Redis的内存而开发的。 ziplist是一系列特殊编码的内存块列表,每个元素的长度不同,例如内存的连续数组,一个ziplist可以包含多个节点(entry )。 ziplist将表中的各项存储在前后连续的地址空间中,各项根据占用的区域采用可变长度编码。

ziplist的主要优点是节省内存,但上面的搜索操作只能按顺序搜索。 你可以从前到后,也可以从后到前。

ziplist的目的是根据一定的规则将数据编码到连续的内存空间中,从而节约内存。 这个结构不擅长变更操作。 数据发生更改时,可能会发生内存realloc,从而导致内存复制。

ziplist 是一个特殊的双向链表

特殊之处在于没有维护双向指针:prev next; 保存上一个条目的长度和当前条目的长度,并根据长度估计下一个元素位于何处。

以牺牲读取性能为代价,确保高效的存储空间。 因为“对于短字符串”存储指针比存储条目长度更占用内存。 这是典型的“时间空间交换”。

ziplist使用局限性

字段,仅在值小时使用ziplist。

源码

typedef struct zlentry { //压缩列表节点unsigned int prevrawlensize,prevrawlen; //prevrawlen是前一个节点的长度,prevrawlensize是指prevrawlen的大小,有1字节和5字节两种不确定长度,len; //len表示当前节点的长度lensize或对len进行编码所需的字节大小unsigned int headersize; //当前节点的header大小非唯一通道编码; //节点编码方式unsigned char *p; //指向节点的指针} zlentry;如何通过一个节点向前跳转到另一个节点?

从指向当前节点的指针e中减去前一个入口的长度而得到的结果是指向前一个节点的地址p。

ziplist连锁更新问题

因为在ziplist中,每个zlentry都包含上一个节点所占的字节数,其值为变长编码。 e1、e2、e3, 如果存在包含E4 .的压缩列表,并且e1节点的大小为253字节,则e2.prevrawlen的大小为1字节,其中e2和e1之间插入新的节点e_new,则e_new编码如果作为3333333的e2的整体长度发生变化,e3.prevrawlen的内存长度发生变化,则e3也需要扩展…….这样,末尾节点或某个节点的prevrawlen本身的长度就会递归,直到前一个节点的变化为止删除254字节节点也是如此,如果操作节点后节点的prevrawlen发生变化,则可能会引起连锁更新。

链接更新最坏的情况下,需要n次空间再配置,但每次空间再配置的最差时间复杂度为o(n ),因此链接更新的总时间复杂度为o ) n^2)。 即使链接更新所涉及的时间复杂度如此高,其引起性能问题的概率也极低。 列表中必须存在多个节点长度接近254的zlentry。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。