压缩列表(ziplist)是列表或字典的底层实现之一。当一个列表只包含少量列表项,并且值的长度较短,或者当一个字典的键值对较少,并且键和值都是较短的字符串,那么Redis就会选择压缩列表作为列表和字典的底层实现

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> LPUSH list y x d
(integer) 3
127.0.0.1:6379> OBJECT ENCODING list
"ziplist"

127.0.0.1:6379> HSET person "name" "Jack"
(integer) 1
127.0.0.1:6379> OBJECT ENCODING person
"ziplist"

压缩列表构成

压缩列表是为了节约内存儿开发的,是由一系列特殊编码的连续内存块组成的顺序性数据结构。一个压缩列表可以包含若干个节点(entry),每个节点可以保存一个字节数组或者一个整数值

上图是压缩列表的构成

属性 类型 长度 用途
zlbytes uint32_t 4字节 记录整个压缩列表占用的内存字节数,在对压缩列表进行内存分配,或者计算zlend的位置时使用
zltail uint32_t 4字节 记录压缩列表尾节点距离压缩列表的起始地址有多少字节。通过这个偏移量,程序可以直接定位尾节点的地址
zllen uint16_t 2字节 记录了压缩列表包含的节点数量。当这个值小于 65535 时,这个属性的值就是压缩列表包含的节点数量;当这个值等于65535时,需要遍历整个压缩列表才能计算得出
entry 列表节点 不定 压缩列表包含的各个节点,节点的长度由节点保存的内容决定
zlend uint8_t 1字节 特殊值 0xFF(十进制255),用于标记压缩列表的末端

下图为一个压缩列表的示例:

  • 列表属性 zlbytes 值为 0x50(十进制80),表示列表总长为80字节
  • 列表属性 zltail 值为 0x3c(十进制60),这表示如果我们有一个起始地址指针 *p,则我们可以直接用这个指针加上 zltail 定位到尾节点的地址

压缩列表节点构成

每个压缩列表节点都可以保存一个字节数组或者一个整数,每个节点都有下面三部分组成:

  • previous_entry_length:记录了压缩列表中前一个字节的长度。用于定位前一个节点的地址;如果前一节点的长度小于254字节,那么该属性需要用1字节长的空间来保存这个长度值;如果前一节点的长度大于等于254字节,则需要用5字节长的空间来保存这个长度值
  • encoding:记录了节点的content属性所保存数据的类型以及长度
  • content:负责保存节点的值,节点值可以是一个字节数组或者整数,值的类型和长度由节点的encoding属性决定。

总结

  • 压缩列表是一种为节约内存而开发的顺序型数据结构。
  • 压缩列表被用作列表键和哈希键的底层实现之一。
  • 压缩列表可以包含多个节点,每个节点可以保存一个字节数组或者整数值。
  • 添加新节点到压缩列表,或者从压缩列表中删除节点,可能会引发连锁更新操作,但这种操作出现的几率并不高。