bigywater.tech
Redis · 10

ListPack 如何替代 ZipList

验证list、hash、zset三种类型的小集合,OBJECT ENCODING是不是真的都统一显示listpack,以及变大之后它们各自走向了哪条路。

0处ziplist
验证这个版本完全不再使用ziplist
3种类型统一listpack
小集合时共用同一种紧凑编码
3条不同的路
变大后分别走向quicklist/hashtable/skiplist

做的事:三种不同类型的小集合,看它们用的是不是同一种编码

list、hash、zset历史上各自有自己的"紧凑编码",验证它们现在是不是统一了。

操作RPUSH mylist a b c HSET myhash f1 v1 f2 v2 ZADD myzset 1 a 2 b OBJECT ENCODING mylist / myhash / myzset

验证:三种类型的小集合,全部是listpack

结果没有一个是"ziplist"。

结果OBJECT ENCODING mylist → :listpack OBJECT ENCODING myhash → :listpack OBJECT ENCODING myzset → :listpack

三种类型用的都是同一个名字——listpack。老版本Redis(7.0之前)这三种类型小数据量时用的是各自独立实现的 ziplist,本文这个Redis 8.10.1已经完全看不到ziplist这个词了——listpack是一种更新、更省内存、编码修复更简单的紧凑结构,统一取代了ziplist在list/hash/zset三个类型里的角色。

验证:变大之后,三种类型走向了三条不同的路

同样从listpack出发,超过各自的阈值后,转成了三种不同的大集合结构。

结果(把三个阈值都手动设成64做对照)list超过阈值 → :quicklist(listpack节点组成的链表) hash超过阈值(65个字段) → :hashtable(真正的哈希表) zset超过阈值(65个成员) → :skiplist(跳表 + 哈希表的组合)

虽然小数据量时三者共享同一个 listpack 编码,但变大之后,各自转向的目标结构完全不同:list变成quicklist(很多个listpack节点串成的链表,适合频繁在两端插入/删除);hash变成hashtable(标准哈希表,适合大量字段的O(1)随机访问);zset变成skiplist(跳表配合哈希表,既要能按分数排序范围查询,又要能O(1)按成员查分数)。

这就是listpack扮演的角色:它只是"数据量小的时候,三种类型共用的一个省内存的紧凑存储层",并不能替代各自类型真正需要的大集合结构——一旦数据变大,各自还是要转向为自己的访问模式量身定做的实现。

分步演示:三种类型共享又分化的编码之路

每一步都是本文上面用redis-cli跑出来的原始结果。

小时候共用listpack,长大后分道扬镳
这一步新验证的类型

    本文用到的工具

    • 本机 Redis 8.10.1 单节点
    • OBJECT ENCODING:对比list/hash/zset的小/大集合编码
    京ICP备2026067502号-1京公网安备11010502063487号