在 Redis 3.0 之前,List 对象的底层数据结构是双向链表或压缩列表;在 Redis 3.2 时,List 对象的底层改为 quicklist 实现
其实 quicklist 就是「双向链表 + 压缩列表」组合,一个 quicklist 就是一个链表,链表中的每个元素又是一个压缩列表
压缩列表通过紧凑型的内存布局节省了内存开销,但如果保存过多的元素会导致性能严重下降(详见)
quicklist 的解决办法:控制每个链表节点中压缩列表的大小和元素个数,来规避「连锁更新」等问题。因为压缩列表元素越少或越小,连锁更新带来的影响就越小
quicklist 结构设计
// quicklist
typedef struct quicklist {
quicklistNode *head; // 链表头
quicklistNode *tail; // 链表尾
unsigned long count; // 所有压缩列表中的总元素个数
unsigned long len; // 压缩列表的个数
...
} quicklist;
// quicklist 节点
typedef struct quicklistNode {
struct quicklistNode *prev; // 前一个节点
struct quicklistNode *next; // 后一个节点
unsigned char *zl; // 指向的压缩列表
unsigned int sz; // 压缩列表的的字节大小
unsigned int count:16; // 压缩列表的元素个数,:16 是指占用 16 bits
...
} quicklistNode;
在向 quicklist 添加元素时,不会像普通的链表那样,直接新建一个链表节点。而是会检查插入位置的压缩列表是否能容纳该元素,如果能容纳就直接保存到该压缩列表,如果不能,才会新建一个新的 quicklistNode 结构
quicklist 会控制 quicklistNode 结构里的压缩列表的大小和元素个数,来减少连锁更新带来的性能影响(注意:不是解决连锁更新的问题,而是降低影响到很小)