快速列表(quicklist )是列表(list)的底层实现之一,当列表中元素较少,并且里面的字符串的长度不长时,Redis 使用的压缩列表(ziplist)来存储的,这个大家都知道了哈,然而当列表中的元素越来越多,或者某一个元素的长度太大时就会使用快速列表来存储元素了。
这里需要说明的一点是 Redis 早期版本存储列表数据结构使用的是压缩列表 ziplist 和普通的双向链表linkedlist,也就是元素少时用 ziplist,元素多时用 linkedlist,但是这种存储结构,每个节点里面光是两个指向前一个节点的 prev 指针和一个指向后一个节点的 next 指针就要占据大量的空间,而且每个节点的内存都是单独分配的,加剧了内存的碎片化,为了尽可能节约内存,在 Redis 的后续版本中(3.2版本后)对列表进行了改造,采用快速列表代替了普通双向列表。
quicklist 是 ziplist 和 linkedlist 的混合体,它将 linkedlist 按段切分,每一段使用 ziplist 来紧凑存储,多个 ziplist 之间使用双向指针串接起来。
quicklistNode 定义:
struct quicklistNode {
quicklistNode* prev;
quicklistNode* next;
ziplist* zl;
int32 size;
int16 count;
int2 encoding;
}
prev 指向前一个节点的指针
next 指向后一个节点的指针
zl 指向压缩列表
size 表示ziplist 的字节总数
count 表示ziplist 中的元素数量
encoding 表示存储形式,原生字节数组还是 LZF 压缩存储
quicklist 定义:
struct quicklist {
quicklistNode* head;
quicklistNode* tail;
long count;
int nodes;
int compressDepth;
}
count 表示元素总数
nodes 表示ziplist 节点的个数
compressDepth 表示LZF 算法压缩深度
quicklist 中的单个ziplist默认长度为 8k 字节,超出了这个字节数,就会新起一个ziplist。
ziplist 的长度由配置参数 list-max-ziplist-size 决定。
压缩
为了进一步节约空间,Redis 还会对 ziplist 使用 LZF 算法进行压缩存储,我们可以配置压缩实际深度,压缩的实际深度由配置参数 listcompress-depth 决定。
quicklist 默认的压缩深度是 0,也就是不压缩。为了支持快速的push/pop 操作,quicklist 的首尾两个 ziplist 不压缩,此时深度就是 1。如果深度为 2,就表示 quicklist 的首尾第一个 ziplist 以及首尾第二个 ziplist 都不压缩。