Redis数据结构之QuickList
从ZipList到QuickList
在ZipList,由于申请的空间是连续的,所以ZipList时比较节省内存的,但是同时带来的一个问题,如果申请内存占用较多,数据量较大时,就会导致无法保证申请到够大的内存空间,申请空间效率降低;
申请内存占用多的情况下可以限制ZipList的长度和entry大小;
数据量较大的情况下可以创建多个ZipList分片来存储数据;
那么多个ZipList之间如何建立联系?显然,链表是个不错的选择。
QuickList就是这样的一个双端链表,链表中每个节点都是一个ZipList;
QuickList的结构
- QuickList链表结构:
typedef struct quicklist {
//头节点指针
quicklistNode *head;
//尾节点指针
quicklistNode *tail;
//所有ziplist的entry的数量
unsigned long count;
// ziplists总数量
unsigned long len;
// ziplist的entry上限,默认值-2
int fill : QL_FILL_BITS;
//首尾不压缩的节点数量
unsigned int compress : QL_COMP_BITS;
//内存重分配时的书签数量及数组,一般用不到
unsigned int bookmark_count: QL_BM_BITS;
quicklistBookmark bookmarks[];
} quicklist;
- QuickList链表节点:
typedef struct quicklistNode {
//前一个节点指针
struct quicklistNode *prev;
//下一个节点指针
struct quicklistNode *next;
//当前节点的ZipList指针
unsigned char *zl;
//当前节点的ZipList的字节大小
unsigned int sz;
//当前节点的ZipList的entry个数
unsigned int count : 16;
//编码方式:1,ZipList; 2,lzf压缩模式
unsigned int encoding : 2;
//数据容器类型(预留):1,其它;2,ZipList
unsigned int container : 2;
//是否被解压缩。1:则说明被解压了,将来要重新压缩
unsigned int recompress : 1;
unsigned int attempted_compress : 1;//测试用
unsigned int extra : 10; /* 预留字段*/
}quicklistNode;
- QuickList和ZipList之间的结构
QuickList优化
-
为了避免ziplist中的entry数量过多,Redis提供了相关配置用于线程quicklist中ziplist大小,配置项 list-max-ziplist-size :
如果为正 ,则代表Ziplist的entry允许的最大个数。 如果为负,则代表Ziplist的最大内存大小,5种情况:(默认-2) -1 :每个ziplist不超过4kb -2 :每个ziplist不超过8kb -3 :每个ziplist不超过16kb -4 :每个ziplist不超过32kb -5 :每个ziplist不超过64kb
-
除了控制Ziplist大小,Quicklist还可以对节点的Ziplist进行压缩,通过配置list-compress-depth来控制。因为链表一般来说首尾访问较多,所以首尾是不压缩的,这个参数是控制首尾不压缩的节点个数。
0 :默认值,不压缩。 1: 表示Quicklist首尾个1个节点不压缩,中间节点压缩。 2: 表示Quicklist首尾个2个节点不压缩,中间节点压缩。