ZipList
ziplist是一种特殊的“双向链表”,由一系列特殊编码的连续内存组成,可以在任意一端进行压入和弹出。
ZipList的结构
ZipListEntry的结构
entry并不像普通双向链表节点用两个指针指向前后节点,为了节省空间。
- previous_entry_length:前一个节点的长度,占1个或5个字节
- 如果前一节点的长度小于254字节,则采用1个字节来保存这个长度值
- 如果前一节点的长度大于254字节,则采用5个字节来保存这个长度值,第一个字节为0xfe,后面四个字节才是真实长度数据
- encoding:编码属性,记录content的数据类型(字符串还是整数)以及长度,占用1个、2个或5个字节
- contents:负责保存节点的数据,可以是字符串或者整数
ZipList连锁更新问题
因为在第一个节点插入了一个254大小的entry,导致后面一个节点的previous_entry_lenghth从1字节变成5字节,导致这个节点也变成254字节大小,所以后面的节点都跟着变大。
QuickList
QuickList是一个双向链表,但是其中的每个节点是ZipList。
为了避免QuickList中的每个ZipList中的entry过多,redis提供了一个配置项:list-max-ziplist-size来限制。
- 如果为正,则代表ZipList的允许的entry个数的最大值。
- 如果为负,则代表ZipList的最大内存大小,分5种情况:
- -1:每个ZipList的内存占用不能超过4kb
- -2:每个ZipList的内存占用不能超过8kb
- -3:每个ZipList的内存占用不能超过16kb
- -4:每个ZipList的内存占用不能超过32kb
其默认值为-2。
除了控制ZipList的大小,QuickList还可以对节点的ZipList做压缩。通过配置项list-compress-depth来控制。因为链表一般都是从首尾访问比较多,所以首尾是不压缩的。这个参数是控制首尾不压缩的节点个数:
- 0:特殊值,代表不压缩
- 1:标识QuickList的首尾各有1个节点不压缩,中间节点压缩
- 2:标识QuickList的首尾各有2个节点不压缩,中间节点压缩
- 依此类推
QuickList的特点
- 是一个节点为ZipList的双端链表
- 节点采用ZipList,解决了传统链表的内存占用问题
- 控制了ZipList大小,解决连续内存空间申请效率问题
- 中间节点可以压缩,进一步节省内存