List 编码是什么
Redis 的 List 有两种内部编码:元素少且小的时候用 listpack(紧凑连续内存),超过阈值后转成 quicklist(双向链表,每个节点又是一个 listpack)。7.2 起 quicklist 的节点统一由 listpack 构成,内存效率比早期的 ziplist 更好。需要强调的是编码只影响内存占用与中间位置操作的常数,与头尾操作无关:LPUSH/RPOP 这类操作始终是 O(1)。
基本信息
| listpack | 元素数量与单个元素都小时使用,紧凑连续 |
|---|---|
| quicklist | 链表 + 节点结构,节点内是 listpack |
| 阈值参数 | list-max-listpack-size,默认 128(正值表示元素个数上限) |
| 负值含义 | 为负时表示按「单个元素的字节大小」限制,不再是元素个数 |
| 观察 | OBJECT ENCODING key;MEMORY USAGE key 看实际占用 |
典型使用场景
- 内存排查:消息队列积压时确认 List 是否已转 quicklist,评估内存水位
- 容量规划:估算单条 List 最多可容纳多少元素,避免形成超大键
- 队列长度治理:把超长 List 拆成多段,降低单个键的内存与删除开销
- 版本升级对比:7.2 前后同一批键的编码与内存差异可作为升级收益依据
- 参数验证:调整 list-max-listpack-size 后用新建键验证是否按新阈值生效
观察编码
观察编码
# 小列表:listpack
RPUSH small 1 2 3
OBJECT ENCODING small # -> listpack
# 查看当前阈值(默认 128)
CONFIG GET list-max-listpack-size
# 插入超过阈值后编码会转为 quicklist
RPUSH big $(seq 1 500)
OBJECT ENCODING big # -> quicklist
# 想知道真实内存占用,别只看编码
MEMORY USAGE big
LLEN big编码对照
| 编码 | 结构 | 内存特点 | 头尾操作 |
|---|---|---|---|
| listpack | 单块连续内存,逐个元素紧凑存放 | 最省,无额外指针 | O(1) |
| quicklist | 双向链表,每个节点是一个 listpack | 节点间有指针开销,按节点分摊 | O(1) |
| 转换方向 | 单向:listpack 转 quicklist 后不回退 | — | — |
list-max-listpack-size 的符号决定语义:正数是「每个节点的元素个数上限」,负数是「每个节点的字节上限」。调参数前先在测试实例上验证当前版本的解释方式。
List 的中间位置操作(LINSERT、LINDEX 大下标、LSET 等)在两种编码下都不是 O(1),超大 List 应避免把中间操作放进高频路径。