Redis 系列 快速列表

开启 redis 探索新篇章

Posted by lichao modified on December 24, 2019

Redis list 数据结构的底层实现之一是 quicklist。 quciklist 是从 3.2 版本加入 Redis 的,用于取代普通的双向链表结构。主要用于减少拥有大量节点的列表的内存使用量。

快速列表

quicklist 是 ziplist 和 linkedlist 的混合体,它将 linkedlist 按段切分,每一段使用 ziplist 来紧凑存储,多个 ziplist 之间使用双向指针组成双向链表。ziplist 本身也是一个能维持数据项先后顺序的列表(按插入位置),而且是一个各个数据项在内存上前后相邻的列表。

1
2
3
4
5
6
7
8
9
struct quicklistNode {
    quicklistNode * prev;
    quicklistNode * next;
    ziplist * zl; // 指向压缩列表
    int32 size; // ziplist 的字节总数
    int16 count; // ziplist 中的元素数量
    int2 encoding; // 存储形式 2bit,原生字节数组还是 LZF 压缩存储
    ...
}
1
2
3
4
5
6
7
8
struct quicklist {
    quicklistNode * head;
    quicklistNode * tail;
    long count; // 元素总数
    int nodes; // ziplist 节点的个数
    int compressDepth; // LZF 算法压缩深度
    ...
}

quicklist 内部默认单个 ziplist 长度为 8k 字节,超出了这个字节数,就会新起一个 ziplist。ziplist 的长度由配置参数list-max-ziplist-size决定。

压缩深度

为了进一步节约空间,Redis 还会对 ziplist 进行压缩存储,使用 LZF 算法压缩,可以选择压缩深度。

quicklist 默认的压缩深度是 0,也就是不压缩。压缩的实际深度由配置参数 list-compress-depth 决定。为了支持快速的 push/pop 操作,quicklist 的首尾两个 ziplist 不压缩,此时深度就是 1。如果深度为 2,就表示 quicklist 的首尾第一个 ziplist 以及首尾第二个 ziplist 都不压缩。

quicklist压缩深度

1
2
3
4
5
6
7
8
struct ziplist {
    ...
}

struct ziplist_compressed {
    int32 size;
    byte[] compressed_data;
}