Skip to content

feat(storage): 持久化实例拓扑并拒绝不安全启动配置 #343

Description

@AlexStocks

问题背景

Kiwi 当前把 key 路由到 RocksDB instance 的逻辑简化为:

slot_id = CRC16-ARC(full_key)
instance_id = slot_id % db_instance_num

当前实现存在三个安全问题:

  1. db_instance_num 没有持久化到数据库目录;
  2. hash 算法、slot 算法和映射版本没有持久化;
  3. 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 官方测试向量;
  • 不能把算法替换当作无状态代码修复。

验收标准

  • db_instance_num、hash/hashtag 版本和 slot map 已持久化;
  • 修改配置实例数后,旧库启动会明确失败而不是重新映射;
  • hash 算法版本不一致会明确失败;
  • 16384 个 slot 都且仅映射到一个有效 instance;
  • slot map checksum、目录完整性和 Manifest 一致性均有启动校验;
  • Manifest/slot map 写入具有崩溃安全性;
  • 空库初始化、正常重启、配置不一致、目录缺失、Manifest 损坏均有测试;
  • 为后续 reshard 提供版本化的数据结构和状态字段;
  • 文档明确禁止直接修改 db_instance_num

非目标

  • 本 Issue 不实现跨多个 RocksDB 的通用分布式事务;
  • 第一阶段可以不完成在线 reshard,但必须先阻止不安全启动;
  • 不在没有版本门禁的情况下切换 CRC 算法。

关联

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions