版本号永远停在 7.2.4,Valkey 两年半重写了 Redis 的半个底座
- Valkey 将 redis_version 冻结在 7.2.4 作为兼容行为快照,对外承诺 drop-in 替换,对内放手重构底座
- 过期结构、哈希表与有序集合、槽位迁移三处核心重写:Volatile Set 时间桶支持字段级过期,rehash 增量页释放消毛刺,整槽原子迁移支撑 2000 节点集群
- 9.1 引入 Lua 模块化、CLUSTERSCAN 跨节点扫键、Space-Saving 算法热点键追踪,性能上 pipeline 预取加 40%、SIMD BITCOUNT 最高快 200%
- 缺失向量检索能力,Active/Active 双活、io_uring 等需求仍在排队,与 Redis 8.x 形成选型分水岭
- 社区近半 commit 来自 AWS 工程师,中立基金会外衣下仍是厂商主导,bus factor 风险值得纳入选型考量
大家好,我是若风。
先看一个有点反直觉的东西。找台装了 Valkey 的机器,连上去敲一句 INFO,redis_version 一栏写的是 7.2.4。
这不是装了老版本,这是 2026 年 9 月刚发的 9.1.2。而且不管你怎么配置,这一栏永远是 7.2.4,src/server.c 第 6262 行写死的不带任何条件。
一个主版本号都跑到 9 的项目,为什么对外报版本时死咬着 7.2.4 不放。答案在 src/version.h 里,那行注释写得直白,Redis OSS compatibility version, should never exceed 7.2.x。兼容版本号永远不许超过 7.2.x,这是写进源码的誓言。
把这个决策看懂,你才能看懂 Valkey 这两年半在干什么。
48 小时里的分家
时间拨回 2024 年 3 月 20 日,Redis Ltd. 宣布放弃 BSD 协议,转向 RSALv2 和 SSPL 双许可,云厂商想继续提供托管 Redis,要么谈商业授权,要么自己动手。两天后的 3 月 22 日,一个 fork 自 Redis 7.2.4(最后一个 BSD 版本)的仓库悄悄建了起来,后来交给 Linux Foundation 托管,改名 Valkey。
站队速度快得惊人。AWS、Google Cloud、Oracle、Snap、Ericsson 相继公开背书,ElastiCache 直接把默认引擎换成了它。到今天我抓数据这会儿,27121 个 star,1306 个 fork,协议还是原来的 BSD-3-Clause。
你想想看,一个数据库项目,出生的第一天就带着数百家公司的生产流量。它没有试错期,第一天就得是 Redis。
所以 Valkey 给自己的定位从头到尾只有一句话,drop-in replacement,直接替换。make install 装完之后,安装目录里会顺手建一组 redis-server、redis-cli 的软链接,指回 valkey 的二进制。你现有的一整套运维脚本、监控探针、客户端库,不用改一行代码。
而版本号冻结就是这套策略最深的一颗钉子。大量客户端库和周边工具会拿版本号做能力判断,见到 8.0、9.0 就启用新语法,见到 7.x 走老路径。Valkey 如果跟着 Redis 的版本号跑,就得追着别人的 release 节奏模拟别人的行为。把版本冻在 7.2.4,等于宣布我只承诺 7.2.4 这个行为快照,多的一概不装。
源码里这条线拉得很清晰。INFO 里的 redis_version 是无条件报 7.2.4,因为几乎所有监控工具都解析这个字段。再往深一层,src/config.c 里还有个 extended-redis-compatibility 开关,默认关闭。src/networking.c 第 5967 行,HELLO 回复版本号的那行代码就一个三元表达式,开关关着就报 valkey 自己的真版本,开着就报 7.2.4,连报错文案都跟着切换,src/server.c 里为 loading 错误、慢脚本错误这些提示各准备了两套措辞。需要骗过某些只认 Redis 的老工具时,一条 CONFIG SET 就能切换。
坦白讲,这是我能想到的对 fork 项目最清醒的身份设计。对外永远扮演 7.2.4,对内放开手脚干自己的。
下面才是这篇文章真正想拆的部分。兼容层冻住了,那底座呢?
底座上的三台手术
答案是动得比谁都狠。翻 unstable 分支的源码树,你会发现 Redis 还是那副老骨架,里面好几处器官已经换过了。
第一台,过期结构
Redis 的键过期有个老缺陷,粒度是整个键。一个 hash 里塞了十万个字段,想做「每个字段独立过期」,原生做不到,只能业务侧起定时任务扫。Valkey 9.0 把这事解决了,一口气加了 HEXPIRE、HSETEX、HGETEX、HTTL 等十一个命令。
真正有意思的是底下的实现。支撑这功能的是 src/vset.c,一个叫 Volatile Set 的自适应结构,光是这个结构的头注释就写了上百行。
它把「什么时候过期」组织成时间桶。桶的粒度不是固定的,最小 16 毫秒,最大 8192 毫秒,靠把过期时间戳向上对齐到 2 的幂次窗口来分桶。临近的过期事件挤在细粒度桶里,远期的自动归到粗粒度桶,扫描时从最近的桶开始捞,天然就有优先级。
更巧的是容器形态。整个结构就一个指针,指针最低 3 位被打上 tag,区分四种状态,指向单个条目的 SINGLE、指向有序数组的 VECTOR、指向哈希表的 HT、指向基数树的 RAX。一个字段过期时就是 SINGLE,两个字段升成 VECTOR,超过 127 个条目升成 RAX。小的场景零开销,大的场景扛得住,中间态全自动流转。
一张图看两层设计。上排是容器怎么随规模升级,下排是时间桶怎么按远近分粒度,扫描那支深蓝箭头永远从最近的桶下手。
复制逻辑也跟着变了。src/t_hash.c 里,HINCRBY 这类命令在主从复制时会改写成 HSETEX 带 PXAT 绝对时间戳的形式,为的是字段上设置的过期时间在 replica 那边不丢。这种细节,没真踩过坑的人写不出来。
第二台,哈希表与有序集合
Redis 7.2 的 dict 哈希表在 rehash 时会有延迟毛刺,桶数组扩容那一下,页分配的抖动直接反映到 P99。Valkey 重写了 src/hashtable.c,9.1 又叠加了增量页释放,把 rehash 期间释放的内存拆成小步走,专门治这个尖刺。
有序集合那边更激进。skiplist 节点原本和数据元素分离,9.1 直接把元素嵌进 skiplist 节点里,省一层指针解引用,skiplist 头部也做了内嵌优化。两个 PR 加起来,ZADD 那条热路径少了不少内存往返。
然后是我最喜欢的一处「诚实现场」。unstable 分支里躺着 src/fbtree.c,一个用 SIMD 加速的 cache-optimized B+tree,头注释说 zset 相关的适配逻辑在 zset_fbtree_adapter.c。我去翻了文件树。
这个文件不存在。t_zset.c 里对 fbtree 的引用次数是零。
也就是说 B+tree 的地基已经打进了主线,但 zset 搬家还在施工。你要问我怎么看,我反倒觉得这是好事,大重构切成小步走,每一步主分支都是可发布状态。但也得承认,看 unstable 源码时你得多个心眼,注释描述的架构和实际落地的架构之间存在时间差。
第三台,槽位迁移
集群扩缩容是 Redis 老痛点。逐键迁移的年代,一个百万成员的大集合能把迁移卡死,客户端还得配合重试。Valkey 9.0 改成整槽原子迁移,传输层直接用 AOF 格式流式发送,大集合按元素逐条传,不再要求目标节点一口气吞下整个键。官方博客给的数字是支持扩到 2000 节点,聚合吞吐超过 10 亿请求每秒。
对运维同学,这个特性的分量可能比前面所有加起来都重。
上面这张图是 unstable 分支 src 目录的真实分层。server.c、cluster.c、t_hash.c 这些老文件一个不少,右边那排 vset、fbtree、space_saving、cluster_migrateslots 全是 fork 之后长出来的新器官。我给这套打法起了个名字,叫「行为冻结,器官替换」,目录结构就是这八个字的证据。
9.1 里几个值得单独拎出来的细节
版本节奏先看一眼。8 月 31 日到 9 月 1 日这两天,8.0.11、8.1.10、9.0.6、9.1.2 排着队发布。往前翻一个多月,7 月 21 日那天一口气发了五个版本,从 7.2.14 一路发到 9.1.1。五条分支同时在维护,backport 的纪律性比很多商业公司都强。
具体功能里我挑三个。
Lua 引擎拆成了模块。原来内嵌在 server 里的脚本引擎,9.1 起挪进独立的 Valkey module,为后面接更多脚本引擎铺路。这个方向跟「去耦合」的大趋势是同频的。
CLUSTERSCAN 命令。跨节点扫键一直是客户端自己拼 MOVE 重定向的逻辑,现在服务端原生支持,配合可配置的 DB hash seed,SCAN 在不同节点上能拿到一致的 key 分布。
热点键追踪的底层数据结构是 src/space_saving.c,实现的是 2005 年那篇经典论文的 Space-Saving 算法,O(K) 内存近似追踪 top-K 频率,双窗口设计,一个 live 窗口累积,一个 frozen 窗口给查询,读的人永远看不到半截数据。算法是老的,工程化是新的。
性能账单也摆一下,都来自 9.0 官方博客。pipeline 内存预取吞吐最高加 40%,零拷贝回复大请求加 20%,Multipath TCP 延迟降 25%,SIMD 版 BITCOUNT 和 HyperLogLog 最高快 200%。
数字都很漂亮。但拆项目不能只看发布会,得看它没什么。
它没做什么
第一个缺口,vector set。
Redis 8.0 在 2025 年就把向量检索做进了内核,VADD、VSIM 直接用。AI 时代越来越多的场景是「缓存旁边还得挂个向量库」,这块需求是真实的。我在 Valkey 的源码树里搜了 vectorset 相关的文件和命令。
零个。
9.1 的 release notes 里也没提。如果你要做 AI 应用的存储选型,这是当下两边最实的分水岭。Valkey 队伍里不可能没人看到这个需求,大概率是在排队。issue 区里挂着 80 条评论的 Active/Active 双活复制请求(#512,2024 年开的)、46 条评论的 io_uring 批量写(#112)、forkless save(#4460),全都还开着。需求排队很长,做核心稳定性的手就没法松,这是 fork 项目现实的节奏。
第二个要说的事实,社区结构。
近三个月 unstable 分支 215 个 commit,头五个人贡献了 99 个,占了 46%。榜首 enjoy-binbin 一个人 53 个,第二名 madolson 15 个。再往下翻这些 ID,一串是 AWS 的工程师,项目的核心 maintainer 也大多来自 AWS。
说好的 Linux Foundation 中立社区,实际上是一支厂商雇佣军在做主力开发。你当然可以说 Redis 原来也是 Redis Ltd. 的员工主导,这没什么不体面,钱的去向决定了代码的去向。但如果你是当年因为「不想被一家厂商绑死」才从 Redis 搬出来的用户,这个事实值得放进你的选型天平。BSD 协议保住了你的自由,bus factor 还是那个味道。
横向摆一张表看会更清楚。
| 项目 | 协议 | 与 Redis 生态关系 | 现状 |
|---|---|---|---|
| Valkey | BSD-3 | 冻结在 7.2.4 行为快照,drop-in | 五分支活跃维护,AWS 主导 |
| Redis OSS | RSALv2/SSPL/AGPLv3 三选一 | 原厂,8.x 加了向量集 | 功能最全,云托管受限 |
| Redict | LGPLv3 | 另一个 fork,更保守 | 社区小,节奏慢 |
| KeyDB | MPL-2.0 | 多线程 fork | Snap 收购后基本停更 |
| Dragonfly | BSL 1.1 | 另起炉灶,多线程架构 | 活跃,但不是 drop-in |
一句话总结这张表,想零成本逃离 Redis 的协议束缚又不丢云厂商支持,Valkey 目前是唯一选项。想要最新最全的功能,还得回 Redis。至于 Redict 和 KeyDB,说句实话已经不在主赛道了。
冻结的那层,才是自由的那层
拆完这个项目,我一直在想它到底给了我们一个什么可带走的东西。
想来想去是这句,兼容层冻结,底座才能自由。
这个模式不只适用于数据库 fork。你做任何「替代品」,都会面临同一道选择题,是追着被替代者的每个新特性跑,把自己活成镜像,还是画一条清晰的兼容线,线以上的行为永久冻结,线以下放手重构。Valkey 选了后者,于是它敢在两年半里换哈希表、换过期结构、换迁移协议,因为客户端看到的永远是那个 7.2.4,里面怎么动都不会外溢。
反过来看,那些试图全兼容的替代品,最后的宿命往往是永远慢半拍的影子。兼容是手段,不是目的,把手段当目的的项目会被手段拖死。
所以回到选型。你的业务如果就是缓存、队列、计数器这些经典场景,Valkey 的成熟度和那五条维护分支给你的安全感,配得上生产环境。如果你的路线图上有向量检索、有多活,那现在还是 Redis 8 的地盘,或者老老实实缓存旁边单挂一个向量库。
源码我放在下面了,纯 C,比你想象的易读。挑一个安静的晚上,从 src/version.h 那行注释开始读起,你会看到一个非常清醒的项目。

评论互动