Valkey 9.0.7(2026-10-27)修了相对过期时间加当前时刻后溢出的问题。最扎眼的行为差在 RESTORE:相对 TTL 大到和当前毫秒时间相加会冲出 signed 64 位时,9.0.6 仍回 OK 却不落键,9.0.7 改回 ERR invalid expire time in 'restore' command。
官方 Release Notes 把这条写在 #4880,顺带 SET/GETEX 与模块 SetExpire 同一路径。同版本还带 GHSA-f4q9-j22m-xqq9 集群 Pub/Sub 超大消息堆溢出,这篇只盯 RESTORE 这条可复现差异。下面用 Spring Boot 4.1.2 + Lettuce 对照 9.0.6 / 9.0.7,输出来自一次 verify.sh。
实验环境
官方镜像抽出的 valkey-server 9.0.6 与 9.0.7,监听 127.0.0.1:16379。应用先 SET foo bar,再 DUMP,删掉键后用相对 TTL 9223372036854775807(即 Long.MAX_VALUE)做 RESTORE,打印回复和 EXISTS。
9.0.6:回复 OK,键却不在
===== Valkey 9.0.6 =====
+ ./bin-9.0.6/valkey-server --port 16379 --save '' --appendonly no --daemonize yes --logfile ./server-9.0.6.log --dir ./data-9.0.6
+ ./bin-9.0.6/valkey-server --version
Valkey server v=9.0.6 sha=00000000:0 malloc=jemalloc-5.3.0 bits=64 build=1f17d480abe8beb6
+ java -jar ./app/target/valkey-restore-overflow-0.0.1-SNAPSHOT.jar
DUMP_LEN=15
RESTORE_TTL=9223372036854775807
RESTORE_REPLY=OK
EXISTS=false
TTL=-2
+ ./bin-9.0.6/valkey-cli -p 16379 SHUTDOWN NOSAVE
RESTORE_REPLY=OK,但 EXISTS=false、TTL=-2。相对 TTL 加上当前时刻溢出成负数后,服务端按“已过期”处理:命令成功,键不保留。
9.0.7:直接报 invalid expire time
===== Valkey 9.0.7 =====
+ ./bin-9.0.7/valkey-server --port 16379 --save '' --appendonly no --daemonize yes --logfile ./server-9.0.7.log --dir ./data-9.0.7
+ ./bin-9.0.7/valkey-server --version
Valkey server v=9.0.7 sha=00000000:0 malloc=jemalloc-5.3.0 bits=64 build=25b7fc669a69a4f2
+ java -jar ./app/target/valkey-restore-overflow-0.0.1-SNAPSHOT.jar
DUMP_LEN=15
RESTORE_TTL=9223372036854775807
RESTORE_ERR=ERR invalid expire time in 'restore' command
EXISTS=false
TTL=-2
+ ./bin-9.0.7/valkey-cli -p 16379 SHUTDOWN NOSAVE
同一条 Spring Boot 调用拿到 ERR invalid expire time in 'restore' command,键仍不存在。迁移或备份工具如果把“RESTORE 回 OK”当成恢复成功,在 9.0.6 上会被这种假成功骗过;升到 9.0.7 后错误会浮出表面。
和站内 redis_exporter 1.96 IO 线程 一样,中间件小版本也值得对着客户端路径跑一遍。Release Notes 还列了 stream 命令触发 WATCH 失效等修复,这里不展开。
一起交流
分享你的思考,让讨论更进一步。