Redis系列(四)底层数据结构之快速列表

前言

Redis 已是你们耳熟能详的东西了,平常工做也都在使用,面试中也是高频的会涉及到,那么咱们对它究竟了解有多深入呢?node

我读了几本 Redis 相关的书籍,尝试去了解它的具体实现,将一些底层的数据结构及实现原理记录下来。面试

本文将介绍 Redis 中底层的 quicklist(快速列表) 的实现方法。 它是 Redis 中列表键的底层实现之一。redis

2020-01-05-16-56-43

能够看到图中,这个键值为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, 也就是普通链表来存储数据有两个弊端:数据结构

  1. 每一个节点都有本身的先后指针,指针所占用的内存有点多,太浪费了。
  2. 每一个节点单独的进行内存分配,当节点过多,形成的内存碎片太多了。影响内存管理的效率。

所以,定义了 quicklist, 将 linkedlist 和 ziplist 结合起来,造成一个,将多个 ziplist 经过先后指针互相链接起来的结构,能够在必定程度上缓解上面说到的两个问题。性能

为了进一步节约内存,Reids 还能够对 ziplist 进行压缩存储,应用 LZF 算法压缩。学习

ziplist 切割大小

既然 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 深度历险:核心原理和应用实践》

matt.sh/redis-quick…


完。

联系我

最后,欢迎关注个人我的公众号【 呼延十 】,会不按期更新不少后端工程师的学习笔记。 也欢迎直接公众号私信或者邮箱联系我,必定知无不言,言无不尽。


以上皆为我的所思所得,若有错误欢迎评论区指正。

欢迎转载,烦请署名并保留原文连接。

联系邮箱:huyanshi2580@gmail.com

更多学习笔记见我的博客或关注微信公众号 < 呼延十 >------>呼延十

相关文章
相关标签/搜索