Redis 系列 紧凑列表

开启 redis 探索新篇章

Posted by lichao modified on December 24, 2019

Redis 5.0 引入了一个新的数据结构 listpack,它是对 ziplist 结构的改进,在存储空间上会更加节省,而且结构上也比 ziplist 要精

listpack 的设计彻底消灭了 ziplist 存在的级联更新行为,元素与元素之间完全独立,不会因为一个元素的长度变长就导致后续的元素内容会受到影响。

1
2
3
4
5
6
struct listpack<T> {
  int32 total_bytes; // 占用的总字节数
  int16 size; // 元素个数
  T[] entries; // 紧凑排列的元素列表
  int8 end; // 同 zlend 一样,恒为 0xFF
}

首先这个 listpack 跟 ziplist 的结构几乎一摸一样,只是少了一个zltail_offset字段。ziplist 通过这个字段来定位出最后一个元素的位置,用于逆序遍历。不过 listpack 可以通过其它方式来定位出最后一个元素的位置,所以zltail_offset字段就省掉了。

1
2
3
4
5
struct lpentry {
int<var> encoding;
optional byte[] content;
int<var> length;
}

元素的结构和 ziplist 的元素结构也很类似,都是包含三个字段。不同的是长度字段放在了元素的尾部,而且存储的不是上一个元素的长度,是当前元素的长度。正是因为长度放在了尾部,所以可以省去了zltail_offset字段来标记最后一个元素的位置,这个位置可以通过total_bytes字段和最后一个元素的长度字段计算出来。

长度字段使用 varint 进行编码,不同于 skiplist 元素长度的编码为 1 个字节或者 5 个字节,listpack 元素长度的编码可以是 1、2、3、4、5 个字节。同 UTF8 编码一样,它通过字节的最高为是否为 1 来决定编码的长度。