redis对外的数据结构类型list的底层是quicklist
quicklist结构的定义
typedef struct quicklistNode {
struct quicklistNode *prev;
struct quicklistNode *next;
unsigned char *zl;
unsigned int sz; /* ziplist size in bytes */
unsigned int count : 16; /* count of items in ziplist */
unsigned int encoding : 2; /* RAW==1 or LZF==2 */
unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */
unsigned int recompress : 1; /* was this node previous compressed? */
unsigned int attempted_compress : 1; /* node can't compress; too small */
unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;
typedef struct quicklistLZF {
unsigned int sz; /* LZF size in bytes*/
char compressed[];
} quicklistLZF;
typedef struct quicklist {
quicklistNode *head;
quicklistNode *tail;
unsigned long count; /* total count of all entries in all ziplists */
unsigned int len; /* number of quicklistNodes */
int fill : 16; /* fill factor for individual nodes */
unsigned int compress : 16; /* depth of end nodes not to compress;0=off */
} quicklist;
list支持的操作有
O(1)时间复杂度的
lpush:在左侧(即列表头部)插入
lpop:在左侧(即列表头部)删除
rpush:在右侧(即列表尾部)插入
rpop:在右侧(即列表尾部)删除
。。。
O(N)复杂度的
lindex:取某个位置的元素
linsert:在某个元素前后插入
。。。
一个有序列表,便于在两端追加和删除,而对中间位置存取的时间复杂度为O(N),这是一个双向链表所具有的特点。
quicklist是一个由ziplist组成的双向链表。即quicklist的每一个节点都是ziplist。
双向链表便于在两端进行push和pop,但是内存开销大:
①每个节点除保存数据之外还要保存两个指针。
②每个节点是单独的内存块,地址不连续,容易产生碎片。
ziplist是一块连续的内存,存储效率高。但是修改不方便,每次数据变动都会引发realloc。尤其当ziplist很长时,realloc可能引发大量数据拷贝,近一步降低性能。
redis.conf的配置,表示系欸但最多包含几个数据项以及两端有多少个节点不压缩
list-max-ziplist-size -2
list-compress-depth 0
list-max-ziplist-size -2
采取正值的时候,表示节点最多包含几个数据项,即ziplist的长度。当取负值时,只能取-1~-5。
-5 每个节点ziplist的大小≤64KB字节(bytes)
-4 32
-3 16
-2 8(默认)
-1 4
list-compress-depth 0
因为列表很长的时候,最可能被访问的数据是两端的数据,为了节省内存可以压缩,参数表示quicklist两端不被压缩的节点个数,采用的压缩算法是LZF,一种无损压缩算法。
0 不压缩(默认)
1 quicklist的两端各有一个节点不压缩
...
n quicklist两端各有n个节点不压缩