redis底层数据结构之快速列表(quicklist)
快速列表(quicklist)
redis3 .2版本之前,List类型数据使用的底层数据结构是压缩列表(ziplist)或双向链表(linkedlist),当列表元素个数比较少并且每个元素占用空间比较小时使用压缩列表;当列表元素个数比较多或者某个元素占用空间比较大的时使用双向链表
redis3 .2版本开始,List类型数据使用的底层数据结构是快速列表
快速列表是以压缩列表为节点的双向链表,将双向链表按段切分,每一段使用压缩列表进行内存的连续存储,多个压缩列表通过prev和next指针组成的双向链
快速列表实质就是 压缩列表+双向链表 的组合,结合了压缩列表和双向链表各自的优点
1 quicklist结构
struct quicklist{
quicklistNode *head;
quicklistNode *tail;
unsigned long count;
unsigned long len;
int fill: 16;
unsigned int compress: 16;
}
其中:
head:头部节点
tail:尾部节点
count:所有节点中元素的总数
len:节点的个数
fill:ziplist节点的最大大小,值默认8kb,大小超出后会新建一个ziplist,对应list-max-ziplist-size参数,占16bit
当数字为负数:
-1:每个ziplist节点大小不能超过4kb(建议)
-2:每个ziplist节点大小不能超过8kb(默认配置)
-3:每个ziplist节点大小不能超过16kb(一般不建议)
-4:每个ziplist节点大小不能超过32kb(不建议)
-5:每个ziplist节点大小不能超过64kb(正常工作量不建议)
当数字为正数:ziplist节点最多包含的元素个数,最大值为215215
compress:节点压缩深度,表示节点是否使用LZF算法压缩,对应list-compress-depth参数,占16bit
数字含义如下:
0:不压缩(默认)
1:quicklist列表的两端各有1个ziplist节点不压缩,中间的节点压缩
2:quicklist列表的两端各有2个ziplist节点不压缩,中间的节点压缩
3:quicklist列表的两端各有3个ziplist节点不压缩,中间的节点压缩
以此类推,最大为 216216
2 quicklistNode结构
typedef struct quicklistNode {
struct quicklistNode *prev;
struct quicklistNode *next;
unsigned char *zl;
unsigned int sz;
unsigned int count : 16;
unsigned int encoding : 2;
unsigned int container : 2;
unsigned int recompress : 1;
unsigned int attempted_compress : 1;
unsigned int extra : 10;
} quicklistNode;
其中:
prev:前一个节点
nex:后一个节点
zl:数据指针,如果当前节点的数据被压缩,指向quicklistLZF结构;否则指向ziplist结构
sz:当前节点存放数据的大小
count:当前节点存放的元素个数,占16bit
encoding:数据是否被压缩:1表示没有压缩;2表示被压缩了而且使用的是LZF压缩算法,占2bit
container:预留字段,表示quicklistNode直接保存数据还是采用ziplist结构或者其他结构来保存数据,2表示使用ziplist结构,默认;1表示使用其他结构,占2bit
recompress:当前节点数据是否被解压过(压缩过的数据是否被查看过,查看时需要解压):1表示被解压过,等待被再次压缩,占1bit
attempted_compress:测试时使用,占1bit
extra:额外扩展位,占10bit
3 ziplist结构
ziplist结构请参考: redis底层数据结构之压缩列表(ziplist)
4 quicklistLZF结构
typedef struct quicklistLZF { unsigned int sz; char compressed[]; } quicklistLZF;
其中:
sz:压缩后的数据大小
compressed:字节数组,压缩后的数据
5 quicklist示意图
存有4个节点,6个元素:两端各有1个节点不压缩,每个节点存有2个元素,
中间2个节点压缩,每个节点存有1个元素