Redis 保留证明与 appendfsync 发布门禁 Delta¶
日期:2026-08-23 状态:已实现,定向验证通过
行为变化¶
| 场景 | 旧行为 | 新行为 |
|---|---|---|
| 已过期日期桶的 max seq | 直接抬高 user_trim_seq 并删除桶证明 |
不改标量 trim;保留证明并按当前 after_seq 判定 CursorExpired |
seq=100 位于旧过期桶、seq=50 位于新存活桶 |
错误把 50 也表达为“已裁剪” | 游标可能跨过旧桶时失败闭合,存活 50 不被标量 trim 伪称已删 |
| V1/缺少桶证明 | 可能继续依赖已删除的证明 | append/scan 拒绝,要求迁移或分发日志重放 |
appendfsync=no/未知/缺失 |
可能通过 AOF 启动检查 | 启动拒绝 |
CONFIG GET appendfsync ACL 拒绝 |
未执行该检查 | 启动拒绝 |
QIM_REDIS_ALLOW_UNSAFE_DEV=1 |
跳过 AOF/noeviction | 同时跳过 appendfsync;仍先拒绝 Cluster,且只允许本地端点 |
| slot 工具 | 对外导出且注释暗示可按槽拆分 | 仅编译于 qstore 测试,明确不得用于生产 Cluster 拆分 |
数据格式与部署动作¶
mbmeta.retention_format_version 从 1 升至 2。部署前必须审计已有 mbmeta:
含 V1 或不成对 bucket_max_seq:<day> / bucket_expires_at:<day> 的用户不能安全滚动
混写。对这部分数据执行既有离线迁移或从分发日志重放后,才允许新版本写入和读取。
Redis 服务账户应在最小 ACL 中授予启动期读取 appendfsync 的 CONFIG GET 权限;发布
配置必须明确为 appendfsync everysec 或 appendfsync always。不提供该权限、设置为
no 或返回未知值均应阻断 ready,而不是降级运行。
定向验证¶
| 检查 | 结果 |
|---|---|
cargo test --locked -p qim-common redis_runtime --lib |
6 通过:允许值、no/未知/缺字段、CONFIG 无权限映射、本地 unsafe-dev 边界及 Cluster 解析门禁。 |
QIM_TEST_REDIS_ADDR=redis://127.0.0.1:<独立端口>/15 cargo test --locked -p qim-store --test redis_store |
16 通过:真实 Redis Lua 覆盖旧过期桶 seq=100 + 新存活桶 seq=50、无标量 TTL trim、缺/旧证明拒绝,以及既有邮箱行为。 |
Cluster 的“unsafe-dev 仍拒绝”真实三节点负向门禁由既有
crates/qim-common/tests/redis_cluster_rejection.rs 与
docs/designs/delta_20260823_redis_cluster_negative_gate.md 持续覆盖;本 Delta 不引入
任何 Cluster 支持。