Redis设计与实现 第 7 章 压缩列表
第 7 章 压缩列表
ziplist 是列表键和哈希表底层实现之一
当一个列表键只包含少量列表项,且每个列表项是小整数值或者长度比较短的字符串时会使用 ziplist
127.0.0.1:6379> rpush lst 1 3 5 10086 "hello" "world"
(integer) 6
127.0.0.1:6379> OBject encoding lst
"ziplist"
7.1 压缩列表的构成
节约内存,一系列特殊编码的连续内存块组成的顺序型数据结构
一个压缩列表可以包含任意多个节点,每个节点可以保存一个字节数组或一个整数值


例子:

7.2 压缩列表节点的构成
每个压缩列表节点可以保存一个字节数组或者一个整数值
字节数组可以是以下一种
- 长度小于等于 63 (2^6 - 1)字节的字节数组
- 16383 (2^14 - 1)
- 4294967295 (2^32 - 1)
整数可以是:
- 4 位行,[0, 12] 的无符号整数
- 1 字节的有符号整数
- 3 字节的有符号数
- int16_t
- int32_t
- int64_t

7.2.1 previous_entry_length
previous_entry_length 字节为单位,记录压缩列表前一个字节的长度,本身长度可以是 1 字节或 5 字节
- 如果前一节点长度小于 254 字节,则为 1 字节
- 如果前一节点长度大于等于 254 字,则为 5 字节,该属性的第一字节会被设置为 0xFE (254)。后面四个字节则用来保存前一节点的长度
可以通过当前节点的起始地址来计算前一个节点的起始地址,压缩列表的从表尾向表头遍历操作就是使用这一原理的,
7.2.2 encoding
encoding 记录节点的 content 属性所保存数据的类型以及长度
- 1 字节、2 字节、或 5 字节,值最高位是 00、01、10的字节数组编码:
- 表示 content 保存的是字节数组,数组长度为去除最高两位后的其他位记录
- 1 字节长,值最高位为 11:
- content 保存的是整数值,值为去除最高两位后的其他位记录

7.2.3 content

7.2.4 连锁更新


假如 e1 - eN 都是 250-253 字节,添加新节点 new ,且大小大于 254 字节,此时 e1 的previous_entry_length 只是 1 字节,于是需要重新分配内存空间,e1 的总长度变化,可能超过 254 字节,于是 e2 变化,直到 eN
这种特殊情况下产生的连续多次空间扩展操作称之为“连锁更新”
同理,删除节点也可能引发连锁更新
连锁更新最坏情况下需要对压缩列表执行 N 次空间重分配操作,每次重分配操作的时间复杂度为 O(n),所以连锁更新最坏情况下是 O(n^2)
虽然时间复杂度高,但几率是佷低的
- 压缩列表恰好多个连续的,长度介于 250 - 253 字节的节点
- 出现连锁更新,但只要被更新的节点少,性能影响不大
ziplistPush 平均复杂度为 O(n)
7.4 压缩列表 API

浙公网安备 33010602011771号