List 的底层结构
Redis 的 List 并不是教科书式的双向链表:它由 quicklist 实现,外层是双向链表,每个链表节点内部是一块 listpack(7.0 之前为 ziplist)。这种设计在指针开销与连续内存的紧凑性之间取平衡:节点越小,链表指针与头部开销越大,但单次插入删除要搬动的字节越少;节点越大,内存越省,但修改时复制成本越高。节点容量由 list-max-listpack-size 控制,正数表示每个节点的元素个数上限(如 128),负数表示字节上限,-1 即 4KB、-2 即 8KB,依此类推。
基本信息
| 适用版本 | Redis 3.2 起(7.0 起节点容器为 listpack) |
|---|---|
| 参数名 | list-max-listpack-size,旧版叫 list-max-ziplist-size |
| 默认值 | -2,即单个节点上限 8KB |
| 修改方式 | CONFIG SET 即时生效,CONFIG REWRITE 落盘 |
| 查看编码 | OBJECT ENCODING key 返回 quicklist |
典型使用场景
- 轻量消息队列:LPUSH 入队、BRPOP 出队,需要评估单元素体积对阻塞时长的影响
- 时间线类列表:只保留最近 N 条,用 LTRIM 控制长度并配合固定节点容量
- 大批量小元素入队:把节点容量调大,可省下每个节点的指针与头部开销
- 高频头部插入的缓冲队列:节点调小能让单次插入搬动的字节更少,延迟更平稳
- 需要按索引访问:LINDEX/LRANGE 是 O(N),靠近两端的访问明显更快
查看与调整
查看与调整
redis-cli CONFIG GET list-max-listpack-size # 当前节点容量阈值
redis-cli CONFIG SET list-max-listpack-size 128 # 正数:每节点最多 128 个元素
redis-cli LPUSH queue a b c # 新建一个 List
redis-cli OBJECT ENCODING queue # quicklist,不是 linkedlist
redis-cli MEMORY USAGE queue # 量化单键占用,再决定是否调阈值
redis-cli CONFIG REWRITE # 确认效果后写入配置文件节点容量取值对照
| 取值 | 含义 | 适用倾向 |
|---|---|---|
| 正数如 128 | 每个节点最多该数量的元素 | 元素体积差异大时更好控制 |
| -1 | 单节点上限 4KB | 节点小、指针开销大、修改延迟更稳 |
| -2(默认) | 单节点上限 8KB | 多数场景的折中值 |
| -3 至 -5 | 16KB 至 64KB | 元素多且小、优先省内存 |
调整 list-max-listpack-size 只影响新建节点与后续分裂出来的节点,已经在内存里的存量 List 不会立即重排;要观察真实收益,需要新建键或把存量键重新写入一遍,再对比 MEMORY USAGE。
从 3.2 到 7.0,List 的对外编码名一直是 quicklist,节点容器由 ziplist 换成了 listpack;看到文档里出现 ziplist 属于历史表述,配置项 list-max-ziplist-size 是同一参数的旧名。