问题背景
Kiwi 当前把 key 路由到 RocksDB instance 的逻辑简化为:
slot_id = CRC16-ARC(full_key)
instance_id = slot_id % db_instance_num
当前实现存在三个安全问题:
db_instance_num 没有持久化到数据库目录;
- hash 算法、slot 算法和映射版本没有持久化;
reshard_slots() 尚未实现。
因此,只要运维修改 db_instance_num,同一个 key 就可能被路由到另一个 RocksDB 目录。旧数据仍位于原 instance,新查询访问新 instance,从客户端看相当于数据丢失。
未来将 CRC16-ARC 改为标准 Redis CRC16-XMODEM + Hashtag 时,也会重新映射已有 key。如果没有落盘版本和迁移门禁,这类变化不能安全上线。
目标
在 Storage 根目录持久化实例拓扑和路由契约,启动时验证配置与落盘状态一致;不一致时直接拒绝打开,禁止静默重映射已有数据。
本 Issue 先完成“安全门禁与显式映射基础”,在线 reshard 可以在此基础上拆分后续 Issue。
建议持久化字段
这些字段应写入统一的 StorageManifest:
db_instance_num
slot_count # Redis-compatible mode 固定为 16384
slot_hash_algorithm # 例如 crc16-arc / crc16-xmodem
slot_hash_version
hashtag_rule_version
slot_map_version
slot_to_instance_checksum
Manifest 的通用版本和迁移策略由 Issue #342 负责。
启动规则
新建空库
- 根据配置创建 instance 目录;
- 生成完整 slot map;
- 持久化 Manifest;
- Manifest 成功后才对外提供服务。
打开已有库
- 配置
db_instance_num 与 Manifest 不一致:拒绝启动;
- hash/hashtag 算法版本不一致:拒绝启动或要求显式迁移;
- slot map 缺失、损坏或 checksum 不一致:拒绝启动;
- Manifest 声明的 instance 目录缺失:拒绝启动;
- 存在 Manifest 未声明的 instance 目录:告警并默认拒绝,避免误接管残留数据;
- 不允许根据当前配置重新计算 slot map 后继续运行。
显式 Slot Map
建议把永久路由从:
instance = slot % db_instance_num
改为:
instance = slot_to_instance[slot]
固定的 16384 slot 空间可以保持 key → slot 稳定;扩缩容只修改部分 slot 的归属,不需要重新计算所有 key。
初始 slot map 可以按 % db_instance_num 均匀生成,但生成后必须持久化,不能在每次启动时根据新配置重算。
为在线 Reshard 预留的状态
后续在线迁移建议使用可恢复状态机:
Stable
-> Preparing
-> Copying
-> CatchingUp
-> Switching
-> Cleaning
-> Stable
每个迁移 slot 至少记录:
slot
source_instance
target_instance
migration_epoch
state
copy_progress
switch_commit_marker
切换前必须完成数据复制和增量追平;旧数据清理只能发生在路由切换持久化并验证成功之后。
与 Redis Hashtag 的关系
标准 Redis Cluster 使用:
CRC16-XMODEM(hashtag_or_full_key) mod 16384
当前 Kiwi 使用 CRC16-ARC 且哈希整个 key,尚不支持 {...} Hashtag。路由算法切换必须:
- 增加
slot_hash_version;
- 提供旧路由识别与迁移方案;
- 使用 Redis 官方测试向量;
- 不能把算法替换当作无状态代码修复。
验收标准
非目标
- 本 Issue 不实现跨多个 RocksDB 的通用分布式事务;
- 第一阶段可以不完成在线 reshard,但必须先阻止不安全启动;
- 不在没有版本门禁的情况下切换 CRC 算法。
关联
问题背景
Kiwi 当前把 key 路由到 RocksDB instance 的逻辑简化为:
当前实现存在三个安全问题:
db_instance_num没有持久化到数据库目录;reshard_slots()尚未实现。因此,只要运维修改
db_instance_num,同一个 key 就可能被路由到另一个 RocksDB 目录。旧数据仍位于原 instance,新查询访问新 instance,从客户端看相当于数据丢失。未来将 CRC16-ARC 改为标准 Redis CRC16-XMODEM + Hashtag 时,也会重新映射已有 key。如果没有落盘版本和迁移门禁,这类变化不能安全上线。
目标
在 Storage 根目录持久化实例拓扑和路由契约,启动时验证配置与落盘状态一致;不一致时直接拒绝打开,禁止静默重映射已有数据。
本 Issue 先完成“安全门禁与显式映射基础”,在线 reshard 可以在此基础上拆分后续 Issue。
建议持久化字段
这些字段应写入统一的
StorageManifest:Manifest 的通用版本和迁移策略由 Issue #342 负责。
启动规则
新建空库
打开已有库
db_instance_num与 Manifest 不一致:拒绝启动;显式 Slot Map
建议把永久路由从:
改为:
固定的 16384 slot 空间可以保持 key → slot 稳定;扩缩容只修改部分 slot 的归属,不需要重新计算所有 key。
初始 slot map 可以按
% db_instance_num均匀生成,但生成后必须持久化,不能在每次启动时根据新配置重算。为在线 Reshard 预留的状态
后续在线迁移建议使用可恢复状态机:
每个迁移 slot 至少记录:
切换前必须完成数据复制和增量追平;旧数据清理只能发生在路由切换持久化并验证成功之后。
与 Redis Hashtag 的关系
标准 Redis Cluster 使用:
当前 Kiwi 使用 CRC16-ARC 且哈希整个 key,尚不支持
{...}Hashtag。路由算法切换必须:slot_hash_version;验收标准
db_instance_num、hash/hashtag 版本和 slot map 已持久化;db_instance_num。非目标
关联