紧凑编码与它的演进
listpack 是 7.0 起取代 ziplist 的顺序紧凑结构:所有元素放在一整块连续内存里,头部记录元素数量与总长度。它出现在小 Hash、小 ZSet 以及 quicklist 的每个链表节点内部。相比 ziplist,listpack 的关键改进是取消了尾部指针记录,修改某个元素不会引发后续元素连锁重写(级联更新),因此在小对象频繁小幅更新的场景下表现更稳定。查看某个键当前使用的编码,用 OBJECT ENCODING。
基本信息
| 出现位置 | 小 Hash、小 ZSet、quicklist 的节点内部 |
|---|---|
| 7.0 变化 | 全面替代 ziplist 作为紧凑编码 |
| 查看方式 | OBJECT ENCODING 返回 listpack |
| 相关阈值 | hash-max-listpack-entries / hash-max-listpack-value |
| 旧命名 | 6.x 及以前对应的是 ziplist |
典型使用场景
- 确认小 Hash 是否仍处于紧凑编码,判断内存优化是否生效
- 排查键占用比预期大:编码已经转成了 hashtable
- 调阈值之前先看现状,避免凭感觉改参数
- 升级到 7.0 后复核编码名称变化,修正监控里的字符串匹配
- 容量估算:紧凑编码与常规编码的内存差距相当明显
查看与对照
查看与对照
redis-cli HSET cfg:app theme dark lang zh
redis-cli OBJECT ENCODING cfg:app # 小对象:listpack
redis-cli ZADD rank 1 a 2 b
redis-cli OBJECT ENCODING rank # 小 ZSet:listpack
redis-cli CONFIG GET hash-max-listpack-entries # 当前字段数阈值
redis-cli MEMORY USAGE cfg:app # 量化单键占用,调优前后对比
redis-cli CONFIG REWRITE # 调整阈值后落盘编码与触发条件
| 编码 | 触发条件 | 内存特征 |
|---|---|---|
| listpack(Hash) | 字段数与值长度均在阈值内 | 连续内存,单键额外开销小 |
| hashtable(Hash) | 字段数或单值长度超出阈值 | 每个字段都有指针开销 |
| listpack(ZSet) | 成员数与成员长度在阈值内 | 连续内存,适合小排行榜 |
| skiplist(ZSet) | 突破阈值后转换 | 支持范围查询,内存开销更大 |
listpack 同样要求整块连续内存,把阈值调得过于激进会让单个对象变大,一次修改需要搬动的字节随之增加,O(N) 操作的阻塞时间也被拉长。调优要结合访问模式,而不是只看内存数字。
从 6.x 升级到 7.0 时,配置项从 ziplist 系列改名为 listpack 系列,部分版本仍保留旧名作为兼容别名。脚本或监控里按字符串匹配编码名称的地方要一并调整,否则判断会静默失效。