Redis/List 数据类型 / quicklist 编码

用分块双端结构保存 Redis List

Redis List 提供左右两端的插入和弹出;在 quicklist 编码下,用带头尾指针的双向节点链组织紧凑数据块。

7.2.0内存管理核验 2026-10-08
相关概念

工程问题#

列表需要从两端更新,又要减少每个短元素独立分配节点的内存开销。列表大小、元素大小与压缩设置都会影响内部表示。

实际实现#

命令层把左、右端转换成 LIST_HEAD/LIST_TAIL,再由 quicklist 分发到头尾操作。常规节点中用 listpack 打包元素;过大的元素可单独存放,两端节点保持未压缩。

处理流程#

  1. 命令确定操作左端还是右端
  2. 按当前编码进入 listpack 或 quicklist 分支
  3. quicklist 直接定位头尾节点
  4. 更新块内元素,必要时增加或移除节点

源码片段#

固定版本 · 原文摘录
src/quicklist.c7.2.0 · L1600–L1613
查看原文件
1600void quicklistPush(quicklist *quicklist, void *value, const size_t sz,1601                   int where) {1602    /* The head and tail should never be compressed (we don't attempt to decompress them) */1603    if (quicklist->head)1604        assert(quicklist->head->encoding != QUICKLIST_NODE_ENCODING_LZF);1605    if (quicklist->tail)1606        assert(quicklist->tail->encoding != QUICKLIST_NODE_ENCODING_LZF);16071608    if (where == QUICKLIST_HEAD) {1609        quicklistPushHead(quicklist, value, sz);1610    } else if (where == QUICKLIST_TAIL) {1611        quicklistPushTail(quicklist, value, sz);1612    }1613}
quicklistPush

where 决定向头部还是尾部插入,头尾节点必须保持未压缩。该入口证明双端操作的分发与端点约束;真正的数据复制、listpack 更新和节点增长在 quicklistPushHead/quicklistPushTail 内完成,因此这里不代表整次插入无条件 O(1)。

完整短函数,保留两端未压缩断言。双端删除由 quicklistPopCustom 的 HEAD/TAIL 分支交叉印证。

收益与取舍#

工程分析

带来的收益

  • 双端定位无需遍历全部节点
  • 常规元素打包存放可减少逐元素指针开销

付出的代价

  • 工程分析:块内更新可能产生数据移动或重新分配
  • 节点容量、元素大小及压缩策略共同影响延迟与空间

可比较的选择

逐元素双向链表节点操作直接,但每个元素分别承担链接和分配开销;紧凑性通常较差。

版本与适用范围#

对应 Redis 7.2.0 的 List,案例重点是 quicklist 编码;该版本还支持独立 listpack 编码。双端队列描述访问接口,quicklist 描述具体表示,不能把所有 List 都画成逐元素链表。

参考来源#

源码、官方文档与原始论文
01
redis · listTypePush / listTypePop

src/t_list.c · listTypePush / listTypePop

源码7.2.0
02
redis · quicklistPush

src/quicklist.c · quicklistPush

源码7.2.0
03
redis · quicklistPopCustom

src/quicklist.c · quicklistPopCustom

源码7.2.0

相关实现与比较#

4 个相关案例
14 个匹配案例