redis数据结构(五) quik list

1.为什么会定义quiklist

  前面已经讲过了redis中list的一个实现ziplist,由于ziplist将所有数据保存在一片连续的内存空间中所以使用ziplist不会照成内存碎片,但是也正是这样导致了ziplist不适合存储过多的数据,因为这会对重新申请内存空间和复制元素造成很大压力.为了存储大量数据,必须使用一个新的数据结构来保存.普通的linkedlist虽然也可以保存大量的数据,但是linkedlist中的每个节点中都保存了前一个节点和后一个节点的指针,而且每个节点都会单独是申请内存空间,这导致了内存使用率较低和内存碎片严重,为了兼顾内存使用率,和解决碎片问题,redis使用了一个这种的办法解决这两个问题,redis中引入了一个新的数据结构quiklist.

  quiklist本质上是inkedlist和ziplist的结合体.quiklist的整体上是一个linkedlist,但是linkedlist中的每个节点都是一个ziplist.就是把linkedlist分段存储,每一段都是一个ziplist.

2.内部结构

  2.1 quicklist

struct quicklist {
    quicklistNode* head; //头节点指针
    quicklistNode* tail; //尾节点指针
    long count; // 元素总数
    int nodes; // ziplist 节点的个数
    int compressDepth; // LZF 算法压缩深度
}

  为了方便从前面和后面插入,遍历链表,quiklist中保存了头节点和尾节点的指针.

  count:quiklist中元素的总个数,这样不通过遍历也可以知道整个quiklist中元素的总数

  nodes:quiklist中节点的个数,即整个quiklist中总共有多少个ziplist节点.

  compressDepth:压缩深度,默认为0,当为0的时候表示不压缩,当为一个大于0的整数时,表示链表两端的几个node不压缩

  

  2.2 quiklistNode

struct quicklistNode {
    quicklistNode* prev;
    quicklistNode* next;
    ziplist* zl; // 指向压缩列表
    int32 size; // ziplist 的字节总数
    int16 count; // ziplist 中的元素数量
    int2 encoding; // 存储形式 2bit,原生字节数组还是 LZF 压缩存储
}

  size:当前节点占用的总字节数,包括了保存的值和头信息的大小

  count:当前节点中元素的总数量

  

3.配置参数

  list-max-ziplist-size 3

    每个ziplist中节点的个数,它可以取正值,也可以取负值。

    当取正值的时候,表示按照数据项个数来限定每个quicklist节点上的ziplist长度。比如,当这个参数配置成5的时候,表示每个quicklist节点的ziplist最多包含5个数据项。

    当取负值的时候,表示按照占用字节数来限定每个quicklist节点上的ziplist长度。这时,它只能取-1到-5这五个值,每个值含义如下:

      -5: 每个quicklist节点上的ziplist大小不能超过64 Kb。

      -4: 每个quicklist节点上的ziplist大小不能超过32 Kb。

      -3: 每个quicklist节点上的ziplist大小不能超过16 Kb。

      -2: 每个quicklist节点上的ziplist大小不能超过8 Kb。(-2是Redis给出的默认值)

      -1: 每个quicklist节点上的ziplist大小不能超过4 Kb。

  list-compress-depth 2 

    这个参数表示一个quicklist两端不被压缩的节点个数。注:这里的节点个数是指quicklist双向链表的节点个数,而不是指ziplist里面的数据项个数。实际上,一个quicklist节点上的ziplist,如果被压缩,就是整体被压缩的。

    参数list-compress-depth的取值含义如下:

      0: 是个特殊值,表示都不压缩。这是Redis的默认值。

      1: 表示quicklist两端各有1个节点不压缩,中间的节点压缩。

      2: 表示quicklist两端各有2个节点不压缩,中间的节点压缩。

      3: 表示quicklist两端各有3个节点不压缩,中间的节点压缩。

      依此类推...

 4.使用

Redis 早期版本存储 list 列表数据结构使用的是压缩列表 ziplist 和普通的双向链表linkedlist,也就是元素少时用 ziplist,元素多时用 linkedlist。

考虑到链表的附加空间相对太高,prev 和 next 指针就要占去 16 个字节 (64bit 系统的指针是 8 个字节),另外每个节点的内存都是单独分配,会加剧内存的碎片化,影响内存管理效率。后续版本对列表数据结构进行了改造,使用 quicklist 代替了 ziplist 和 linkedlist。现在list只是用quiklist保存

posted on 2022-04-01 00:51  monkeydai  阅读(249)  评论(0编辑  收藏  举报

导航