Redis 已是你们耳熟能详的东西了,平常工做也都在使用,面试中也是高频的会涉及到,那么咱们对它究竟了解有多深入呢?node
我读了几本 Redis 相关的书籍,尝试去了解它的具体实现,将一些底层的数据结构及实现原理记录下来。面试
本文将介绍 Redis 中底层的 quicklist(快速列表) 的实现方法。 它是 Redis 中列表键的底层实现之一。redis
能够看到图中,这个键值为listkey
的 list 内部使用的编码方法就是 quicklist.算法
quicklist 是 ziplist 和 linkedlist 的一个结合体。它的结构定义以下:后端
struct ziplist_compressed{
int32 size;
byte[] compressed_data;
}
struct quicklistNode {
quicklistNode* prev;
quicklistNode* next;
// 指向压缩列表
ziplist* zi;
// ziplist 的字节总数
int32 size;
// ziplist 的元素总数
int 16 count;
// 存储形式,是原生的字节数组,仍是 LZF 压缩存储
int2 encoding;
}
struct quicklist{
// 头结点
quicklistNode* head;
// 尾节点
quicklistNode* tail;
// 元素总数
long count;
// ziplist 节点的个数
int nodes;
// LZF 算法压缩深度
int compressDepth;
}
复制代码
从结构定义中能够看到,quicklist 的定义和 链表的很像,本质上也是一个双端的链表,只是把普通的节点换成了 quicklistNode, 在这个节点中,保存的不是一个简单的值,而是一个 ziplist.数组
为何要定义一个 quicklist, 列表结构还不够多吗???微信
纯粹的使用 Linkedlist, 也就是普通链表来存储数据有两个弊端:数据结构
所以,定义了 quicklist, 将 linkedlist 和 ziplist 结合起来,造成一个,将多个 ziplist 经过先后指针互相链接起来的结构,能够在必定程度上缓解上面说到的两个问题。性能
为了进一步节约内存,Reids 还能够对 ziplist 进行压缩存储,应用 LZF 算法压缩。学习
既然 quicklist 本质上是将 ziplist 链接起来,那么每一个 ziplist 存放多少的元素,就成为了一个问题。
过小的话起不到应有的做用,极致小的话(为 1 个元素), 快速列表就退化成了普通的链表。
太大的话性能太差,极致大的话(整个快速列表只用一个 ziplist), 快速列表就退化成了 ziplist.
quickli 内部默认定义的单个 ziplist 的大小为 8k 字节
. 超过这个大小,就会从新分配一个 ziplist 了。这个长度能够由参数list-max-ziplist-size
来控制。
前面提到了,quicklist 能够对 ziplist 来进行压缩,并且能够指定压缩深度。(由list-compress-depth
参数决定).
默认的压缩深度为 0, 也就是全部的节点都不压缩。
为了支持快速的 push/pop 操做,quicklist 两端的第一个 ziplist 不进行压缩,这时压缩深度为 1.
若是压缩深度为 2, 则是两端各自两个 ziplist 不压缩。
由于若是将一个 ziplist 压缩,那么要从它里面读取值,必然要先解压,会形成性能变差,所以能够将两端即将被操做的节点不压缩,其余的选择压缩。
总结,为了解决 linkedlist 的双向指针占用内存过多,以及 ziplist 数据量太大性能就变差的问题,结合他们两个产出了新的数据结构,也就是 quicklist
.
它将多个 ziplist 经过先后节点的指针链接起来,在必定程度上解决了上面的问题,提升了 Redis 的响应速度。
《Redis 的设计与实现(第二版)》
《Redis 深度历险:核心原理和应用实践》
完。
最后,欢迎关注个人我的公众号【 呼延十 】,会不按期更新不少后端工程师的学习笔记。 也欢迎直接公众号私信或者邮箱联系我,必定知无不言,言无不尽。
以上皆为我的所思所得,若有错误欢迎评论区指正。
欢迎转载,烦请署名并保留原文连接。
联系邮箱:huyanshi2580@gmail.com
更多学习笔记见我的博客或关注微信公众号 < 呼延十 >------>呼延十