很长一段时间里,只要项目需要缓存、分布式锁、排行榜、会话存储或延迟队列,Redis 几乎都是默认答案。
2024 年 3 月,Redis 宣布从 7.4 开始采用 RSALv2 与 SSPLv1 双重源码可用许可证。Linux Foundation 随后推动成立 Valkey 项目,基于 Redis OSS 7.2.4 的代码继续演进。Redis 后来又在 2025 年为 Redis 8 增加了 AGPLv3 许可证选项,但此时 Valkey 已经形成了独立的社区、版本和技术路线。(Redis)
刚诞生时,Valkey 最重要的标签是“Redis 兼容替代品”。到了 9.1,这个描述已经不够准确。
Valkey 9.1 于 2026 年 5 月发布,由超过 80 位贡献者共同完成,改动覆盖安全、可观测性、I/O 性能、内存效率、新命令和集群工具。它正在从一个兼容分支,逐渐成长为一套拥有独立工程取舍的高性能键值数据库。(Valkey)
本文不讨论“Redis 和 Valkey 谁一定更好”,而是回答三个更实际的问题:
- Valkey 9.1 到底改变了什么?
- 现有 Java 项目接入它需要改多少代码?
- 一个正在运行的 Redis 项目,应该怎样安全迁移?
一、先划清边界:兼容不等于永远完全一致
Valkey 7.2.4 直接继承自 Redis OSS 7.2.4,因此 Redis OSS 7.2 及更早版本与 Valkey 之间具有较完整的兼容基础。
这种兼容不仅是命令名称相似,还包括多个层面:
| 兼容层面 | 具体表现 |
|---|---|
| 网络协议 | 支持 RESP2 和 RESP3 |
| 客户端 | 支持 Redis OSS 7.2 的客户端通常可以直接连接 |
| 配置文件 | 支持 Redis OSS 7.2 的常用配置项 |
| 持久化 | 可以读取对应版本的 RDB 和 AOF 文件 |
| 命令行工具 | redis-cli 可以连接 Valkey,valkey-cli 也可以连接 Redis OSS |
| Lua 脚本 | 原有 redis 命名空间脚本可以继续运行 |
| 模块接口 | 基于旧版 RedisModule_ API 编写的模块通常可以继续加载 |
但这里有一个非常重要的版本边界:Redis Community Edition 7.4 及以后版本生成的数据文件,不能直接通过 RDB 或 AOF 文件迁移到 Valkey。
因此,“Valkey 可以无缝替换 Redis”只对特定版本和特定功能范围成立。Redis OSS 7.2 及以前版本的迁移相对直接,而 Redis CE 7.4 之后通常需要逻辑迁移、应用双写或专门的数据同步方案。(Valkey)
还有一个容易误判的细节:为了兼容部分旧客户端,Valkey 的 INFO 结果可能继续返回 redis_version:7.2.4。识别真实服务端时,应同时检查 server_name 和 valkey_version,不能只读取 redis_version。(Valkey)
二、Valkey 9.1 的安全升级,不只是增加几个配置项
1. ACL 可以限制到具体数据库
过去的 ACL 可以限制用户执行哪些命令、访问哪些 Key,但对逻辑数据库的控制不够细。
Valkey 9.1 增加了数据库级 ACL,可以限制某个账号只能访问指定编号的数据库。例如,只允许订单服务访问数据库 0:
ACL SETUSER order-service on >StrongPassword +@read +@write ~order:* db=0
这样即使多个业务共用一个 Valkey 实例,也可以从数据库编号、Key 前缀和命令类别三个维度共同限制权限。
对于中小型系统,这种能力可以降低账号误用风险;对于多租户平台,它则意味着权限边界不必完全依赖应用代码维护。(Valkey)
不过,逻辑数据库不能真正替代实例级隔离。不同租户仍然共享内存、CPU、连接数和持久化资源。对安全性、资源隔离要求较高的业务,仍然应该使用独立实例或独立集群。
2. Lua 从内核能力变成独立模块
Lua 脚本一直是 Redis 生态中的重要能力,分布式锁释放、限流、库存扣减等场景都经常依赖它。
但脚本引擎也意味着更大的执行和安全边界。Valkey 9.1 将 Lua 从核心服务中拆分为独立模块,默认场景仍然可以保持兼容,但不需要脚本的部署可以选择不加载 Lua,从而减少服务端攻击面。
同时,INFO 增加了脚本引擎相关信息,运维人员可以明确知道当前实例加载了哪些脚本能力。(Valkey)
这项变化提醒我们:升级到 9.1 之前,不能只检查普通命令,还应盘点项目中的 Lua 脚本、脚本缓存和客户端 EVALSHA 调用。
3. TLS 证书轮换不再依赖重启
Valkey 9.1 可以通过 INFO 查看 TLS 证书过期时间,并支持在后台自动重新加载证书。
这意味着证书更新后,不必为了让新证书生效而重启整个缓存实例。同时,它还支持通过证书 SAN URI 进行 TLS 身份认证,更便于接入基于工作负载身份的 mTLS 体系。(Valkey)
对于缓存服务来说,证书轮换看似是一个小功能,但证书过期导致的连接中断,往往会迅速放大为数据库流量激增、接口超时和连锁故障。
三、CPU 接近 100%,不一定代表 Valkey 已经跑满
排查缓存性能问题时,人们经常先看 CPU。
但 Valkey 的主线程和 I/O 线程可能采用忙等待方式等待任务。线程即使没有真正处理大量命令,也可能在操作系统层面呈现较高 CPU 使用率。
因此,仅凭服务器 CPU 接近 100%,不能直接判断实例已经饱和。
Valkey 9.1 增加了主线程和 I/O 线程的累计使用指标,可以帮助运维人员区分两种情况:
- 线程只是处于忙等待状态;
- 线程确实在持续处理大量请求。
同时,Valkey 9.1 支持直接输出 JSON 格式日志:
log-format json
启用后,每一行日志都是一个独立 JSON 对象,可以直接被 Filebeat、Fluent Bit、Vector、Loki 或其他日志平台采集,不再需要为传统文本日志维护复杂的正则表达式。(Valkey)
一个完整的 Valkey 可观测体系,不应该只有 CPU 和内存,还应同时覆盖:
| 维度 | 建议关注的内容 |
|---|---|
| 请求性能 | 吞吐量、平均延迟、P95、P99、最大延迟 |
| 线程状态 | 主线程使用情况、I/O 线程使用情况 |
| 内存 | 已用内存、峰值内存、碎片率、淘汰数量 |
| 连接 | 当前连接、拒绝连接、阻塞客户端 |
| 缓存效果 | 命中数、未命中数、命中率 |
| 持久化 | RDB 状态、AOF 重写状态、最后成功时间 |
| 复制 | 复制延迟、连接状态、复制积压缓冲区 |
| 安全 | 认证失败、ACL 拒绝、证书剩余有效期 |
四、2.1 万还是 210 万?性能数据必须看测试条件
Valkey 9.1 官方测试曾在单实例上达到每秒 210 万次请求,但这个结果有明确条件:
- 数据大小为 512 字节;
- 使用 9 个 I/O 线程;
- Pipeline 深度为 10;
- 测试的是特定硬件与特定负载模型。
因此,这个数字证明的是 Valkey 9.1 的性能上限和多线程改进效果,而不是所有项目升级后都能直接达到 210 万 QPS。(Valkey)
9.1 中比较有代表性的性能改进包括:
| 改进方向 | 官方测试结果 |
|---|---|
| 新的 I/O 线程通信模型 | 部分负载吞吐量最高提升约 17% |
XRANGE、XREVRANGE |
最高提升约 30% |
字符串 GET |
部分场景最高提升约 30% |
| 硬件时钟默认启用 | GET、SET 整体最高提升约 3% |
| 小字符串内存占用 | 部分场景明显下降 |
| 跳表结构 | 排行榜等有序集合场景减少内存占用 |
这些优化并不是让每条命令都获得相同提升,而是分别针对网络通信、数据编码、时间调用、Stream 热路径和跳表查询进行了改进。
真正评估升级价值时,应把自己的命令比例带入测试。例如:
- 会话缓存主要关注
GET、SET、TTL 和淘汰; - 排行榜主要关注
ZADD、ZRANGE、ZRANGEBYSCORE; - 消息流主要关注
XADD、XREADGROUP、XRANGE; - 分布式锁主要关注延迟尾部,而不是最高吞吐量。
五、内存优化可能比吞吐量提升更有价值
对于生产缓存,真正昂贵的资源往往不是 CPU,而是内存。
Valkey 9.1 对小字符串的内部对象布局进行了优化。过去,使用 embstr 编码的小字符串对象仍然保留了一个可以通过地址计算得到的指针。9.1 移除了这个冗余指针,并将 embstr 的适用范围提升到更大的对象。
在官方测试中,小字符串对象的内存开销下降约 17% 至44%,平均约为 26%。对于使用跳表编码的有序集合,长度在 10 至40 字节之间的成员,每个成员大约可以减少 6 至8.5 字节开销,降幅约为 11% 至15%。具体效果会受到 Key 长度、Value 长度、编码方式以及 jemalloc 内存分级影响。(Valkey)
假设系统存在 5000 万个能够节省 8 字节的小对象,仅结构层面的理论节省就可以达到约 400MB。
不过,实际内存节省不能只靠乘法估算。jemalloc 会按照固定大小等级分配内存,结构体减少 8 字节后,只有跨过某个分配等级边界,进程实际占用才会明显下降。
升级前后可以使用下面两个命令抽样验证:
MEMORY USAGE session:abc123
OBJECT ENCODING session:abc123
建议分别挑选以下类型的代表性数据:
- 短字符串;
- 较长的序列化对象;
- 带有过期时间的会话;
- 大型 Hash;
- 排行榜使用的 Sorted Set;
- Stream 消息。
不要只比较实例总内存,因为后台任务、碎片率、Key 数量和测试数据差异都可能干扰结果。
六、三个新命令,减少业务代码中的“伪原子操作”
1. HGETDEL:读取并删除 Hash 字段
过去,如果业务需要读取某个 Hash 字段后立即删除,通常要执行 HGET 和 HDEL,或者使用事务、Lua 脚本保证中间状态不被其他请求打断。
Valkey 9.1 增加了 HGETDEL,可以在一个命令中完成读取和删除:
HSET job:42 status "pending" payload "{\"type\":\"send_email\"}" retries "3"
HGETDEL job:42 FIELDS 2 status payload
它适合一次性任务参数、临时授权信息和消费后即删除的数据,但不能直接替代完整消息队列,因为它本身不提供消费确认、重试和死信机制。
2. MSETEX:批量写入并设置统一过期时间
多个缓存数据需要同时写入且使用相同 TTL 时,过去通常要通过多条 SETEX,或者组合 Pipeline、MSET 和 EXPIRE。
现在可以直接执行:
MSETEX 3 session:a "user:1" session:b "user:2" session:c "user:3" EX 3600
它可以减少网络往返,也能避免应用在批量写入过程中遗漏某个 Key 的过期时间。
3. CLUSTERSCAN:统一扫描整个集群
传统 Redis Cluster 中,普通 SCAN 只能扫描当前连接节点负责的数据。想遍历整个集群,客户端必须获取全部主节点,然后分别执行 SCAN 并合并结果。
Valkey 9.1 增加了 CLUSTERSCAN:
CLUSTERSCAN 0 MATCH "session:*"
它为集群运维、数据排查和迁移工具提供了统一入口,还可以按照 Key 类型或槽位进行过滤。(Valkey)
不过,CLUSTERSCAN 仍然不应该被当成业务查询接口。集群中存在数千万个 Key 时,全量扫描依然会消耗 CPU、网络和客户端内存。正确做法是使用游标分批处理,并避开业务高峰。
七、Java 项目接入 Valkey,需要修改多少代码
从协议层面看,大部分 Java 应用并不关心服务端叫 Redis 还是 Valkey。
只要应用使用的是 Redis OSS 7.2 及以前的通用命令,现有客户端通常可以直接连接 Valkey。Valkey 官方客户端列表中也提供了 valkey-java 和 Valkey GLIDE Java 等选择,其中 GLIDE Java 支持 Valkey 7.2 及以上版本。(Valkey)
对于使用 Spring Data Redis 的项目,最小改动方案通常只是切换连接地址:
spring:
data:
redis:
host: valkey
port: 6379
password: ${VALKEY_PASSWORD}
timeout: 2s
配置名称中继续出现 redis 并不代表连接的服务端必须是 Redis。Spring Data Redis 提供的是基于 Redis 协议和数据结构的抽象,底层仍然通过客户端与兼容服务通信。(Home)
Java 项目可以根据迁移阶段选择不同策略:
| 策略 | 适用场景 | 改造成本 |
|---|---|---|
| 保留现有客户端 | 只使用通用命令,希望快速验证 | 低 |
| 更换为 Valkey 官方客户端 | 新项目或准备长期使用 Valkey | 中 |
| 封装统一缓存访问层 | 需要兼容 Redis 和 Valkey | 中 |
| 大量使用 Valkey 9.x 新命令 | 已确定不再回退旧版本 | 较高 |
更稳妥的做法,是把 Valkey 特有命令封装在 Repository 或基础设施层,而不是让业务代码直接到处调用 HGETDEL、MSETEX。
例如,业务层只依赖下面这样的语义接口:
public interface TemporaryJobRepository {
Optional<JobPayload> consume(String jobId);
void saveBatch(Map<String, JobPayload> jobs, Duration ttl);
}
底层可以根据服务端能力选择 Lua、事务或 Valkey 新命令。这样即使未来切换客户端或存储引擎,也不需要修改大量业务代码。
八、生产迁移优先使用复制,而不是直接复制文件
Valkey 官方提供了三类迁移方案:
| 迁移方式 | 停机时间 | 适用场景 |
|---|---|---|
| 复制 RDB 文件 | 较长 | 数据量不大、允许停机 |
| Redis 到 Valkey 复制 | 较短 | 持续写入的生产系统 |
| 迁移指定 Key | 可控 | 只迁移部分业务数据 |
对于 Redis OSS 7.2 及以前版本,生产环境通常更适合采用复制迁移:先把 Valkey 配置为 Redis 的副本,完成全量和增量同步,再切换应用连接并将 Valkey 提升为主节点。(Valkey)
flowchart LR
A[盘点版本与依赖] --> B[搭建兼容性环境]
B --> C[将 Valkey 配置为副本]
C --> D[完成全量与增量同步]
D --> E[校验键值与过期时间]
E --> F[灰度切换应用连接]
F --> G[提升 Valkey 为主节点]
G --> H[观察后关闭旧实例]
迁移前必须完成的盘点
不能只记录 Redis 版本,还应检查:
- 单机、Sentinel 还是 Cluster;
- RDB、AOF 以及重写策略;
- 客户端类型和版本;
- 是否使用 Lua 脚本;
- 是否加载第三方模块;
- 是否依赖特殊命令;
- Key 数量、数据类型和 TTL 分布;
- 最大 Value、大型 Hash、大型 Set 和热 Key;
- 内存淘汰策略;
- 监控、备份和故障转移流程。
同步完成后,不能只比较 Key 数量
DBSIZE 或 INFO KEYSPACE 相同,只能说明 Key 数量基本一致,不能证明数据完全正确。
至少还要验证:
- 不同数据类型的抽样值;
- TTL 是否保持;
- Stream 消费组和待确认消息;
- Lua 脚本是否能够执行;
- 模块数据能否读取;
- Cluster 槽位是否完整;
- 热 Key 是否存在异常;
- 复制延迟是否归零;
- 应用错误率和超时率是否变化。
切换期间仍然可能丢失最后一小段写入
官方迁移说明也提醒,在 Redis 仍有写请求、而副本尚未完全追平时关闭原节点,仍然存在数据丢失风险。(Valkey)
因此,关键系统在最终切换前应安排一个短暂的写入冻结窗口:
- 暂停或排空写请求;
- 确认复制状态正常;
- 确认偏移量不再变化;
- 切换应用连接;
- 将 Valkey 提升为主节点;
- 恢复写入。
九、保留回滚能力,比快速使用新命令更重要
迁移完成后,很多团队会立即使用 Valkey 9.1 的新命令。
这会让回滚变得更加困难。
旧版 Redis 并不认识 HGETDEL、MSETEX、CLUSTERSCAN 等 Valkey 新命令。更重要的是,一旦新系统承接了持续写入,原 Redis 实例中的数据就会逐渐落后。
因此,生产迁移建议分成两个阶段。
第一阶段:只替换服务端
- 保留原有命令集;
- 不修改数据模型;
- 不立即使用 Valkey 特有能力;
- 观察延迟、错误率、内存和持久化;
- 保留旧实例和原始备份。
第二阶段:关闭回滚窗口
确认系统稳定后,再逐步启用:
- 数据库级 ACL;
- JSON 日志;
- Valkey 专属监控指标;
HGETDEL;MSETEX;- 原子槽位迁移;
- 新的集群运维能力。
这种方式虽然比“一次性升级并改造所有代码”慢一些,但可以把服务端迁移风险与业务代码改造风险分开。
对于特别核心的系统,还可以采用更保守的两阶段版本路线:
Redis OSS 7.2 → Valkey 7.2 → Valkey 9.1
这样可以先完成项目和治理体系迁移,再单独验证跨大版本升级。Valkey 官方也建议谨慎处理大版本升级,并优先升级副本,再升级主节点。(Valkey)
十、不要用默认压测结果做容量规划
Valkey 自带 valkey-benchmark,但直接运行默认命令,得到的结果通常不能代表真实业务。
默认测试主要反复访问同一个 Key,Value 只有几个字节,而且没有启用 Pipeline。它回答的是“当前机器在某个简单模型下能跑多快”,而不是“订单系统迁移后能承受多少流量”。(Valkey)
一个更接近实际缓存负载的示例是:
valkey-benchmark \
-t set,get \
-r 500000 \
-d 512 \
-P 8 \
-n 2000000 \
-q
其中:
-r 500000表示使用较大的随机 Key 空间;-d 512表示 Value 大小为 512 字节;-P 8表示 Pipeline 深度为 8;-n 2000000表示执行 200 万次请求。
压测时应保证 Redis 与 Valkey 使用:
- 相同硬件;
- 相同数据集;
- 相同客户端数量;
- 相同 Pipeline 深度;
- 相同持久化策略;
- 相同网络环境;
- 相同预热时间;
- 相同测试时长。
最终至少比较以下指标:
| 指标 | 关注原因 |
|---|---|
| 吞吐量 | 判断整体处理能力 |
| P50 | 观察典型请求体验 |
| P95、P99 | 发现排队和长尾延迟 |
| 最大延迟 | 发现持久化、扩容和重哈希抖动 |
| CPU | 判断主线程或 I/O 线程瓶颈 |
| 内存 | 评估真实容量变化 |
| 淘汰数量 | 判断缓存是否接近上限 |
| 错误率 | 发现连接和超时问题 |
| 复制延迟 | 判断高可用风险 |
需要特别注意,Pipeline 越深,吞吐量通常越高,但单条请求等待时间也可能增加。不能为了得到更漂亮的 QPS,使用远高于生产客户端的 Pipeline 深度。(Valkey)
十一、哪些项目值得迁移,哪些项目不必着急
比较适合评估 Valkey 的场景
- 当前运行 Redis OSS 6.x 或7.2;
- 大量存储短字符串和会话数据;
- 排行榜使用大量 Sorted Set;
- 对开源治理和许可证有明确要求;
- 希望降低小对象内存开销;
- 希望获得更细粒度 ACL;
- 需要结构化 JSON 日志;
- Cluster 扩缩容和槽位迁移频繁;
- 愿意投入时间完成真实负载测试。
Valkey 9.0 已引入原子槽位迁移,9.1 又在命令行工具中增加相关支持,可以降低集群重新分片过程中部分 Key 已迁移、部分 Key 尚未迁移带来的复杂状态。(Valkey)
不建议立即迁移的场景
- 当前系统长期稳定,负载和成本都没有压力;
- 使用 Redis CE 7.4 及以后版本;
- 严重依赖 Redis 新版本特有功能;
- 使用大量商业模块或私有模块;
- Lua 脚本和客户端行为缺少测试;
- 没有预发布环境;
- 没有监控、备份和回滚方案;
- 迁移目的只是追求官方 QPS 数字。
数据库迁移本身不会直接产生业务价值。只有当它能够解决许可证、成本、性能、安全、扩容或运维问题时,迁移才值得承担风险。
十二、结语
Valkey 9.1 最值得关注的,并不是单实例每秒 210 万次请求这个数字。
真正有价值的是它背后的工程变化:
- 小对象布局减少内存浪费;
- I/O 线程模型提高多核利用率;
- 主线程指标减少 CPU 误判;
- JSON 日志降低采集成本;
- 数据库级 ACL 收紧权限边界;
- TLS 热更新降低证书轮换风险;
- 新命令减少应用层多步骤操作;
- 集群工具逐渐补齐复杂运维能力。
对于 Redis OSS 7.2 及以前版本的项目,Valkey 已经是一个值得认真评估的生产选项。但“协议兼容”并不代表“迁移零风险”,真正可靠的升级仍然需要版本盘点、数据验证、灰度切换、真实压测和明确的回滚窗口。
最稳妥的迁移,不是把 Redis 地址改成 Valkey 地址后直接上线。
而是先证明旧功能没有变化,再决定是否使用新能力。

评论区 1