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 都不压缩。
1
2
3
4
5
6
7
8
struct ziplist {
...
}
struct ziplist_compressed {
int32 size;
byte[] compressed_data;
}