
Multi-Raft 中的 Region 合并与两阶段提交协调在分布式数据库如 TiKV、CockroachDB的 Multi-Raft 体系中分片机制是动态自适应的当数据量膨胀时Region 会自动**分裂Split**为两个小分片而当业务大量删除历史数据、或者在大促结束后数据量急剧缩减时集群中会产生海量数据量极小如不足 10MB的“空洞分片”。成千上万个稀疏小 Region 的存在会造成严重的资源浪费每个 Region 都需要维护独立的 Raft 心跳与 Raft 日志状态机白白浪费海量的 CPU 周期与网络心跳带宽降低跨分片范围扫描Range Scan的查询性能。为了收缩集群拓扑、回收空洞资源Multi-Raft 系统必须支持Region 合并Region Merge。然而与简单的本地 Region 分裂不同Region 合并跨越了两个完全独立的 Raft 状态机源 Region 与 目标 Region如果合并协调不当极易在两个独立 Raft 组之间引发致命的状态不一致与数据丢失。深入剖析基于两阶段协调Two-Phase Coordination / Commit-Merge的 Multi-Raft Region 合并机制是掌握分布式共识高级架构的必由之路。-------------------------------------------------------------------------- | Multi-Raft Region 合并 (Merge) 两阶段执行全景 | -------------------------------------------------------------------------- | 初始状态: | | Region A (区间: [a, m), 仅剩 5MB 数据, 源 Region) | | Region B (区间: [m, z), 目标 Region) | -------------------------------------------------------------------------- | 阶段一: 准备阶段 (PrepareMerge on Region A) v | 1. Region A Leader 发起 Raft 提案: PrepareMerge(Target: Region B) | | 2. Region A 多数派提交该日志并锁定本地状态机: | | - 停止接收任何新的客户端写请求! | | - 递增 Region A 的 Epoch Version | -------------------------------------------------------------------------- | 阶段二: 提交合并阶段 (CommitMerge on Region B) v | 3. Region A 向 Region B 发送内部 RPC 传递合并上下文与当前状态机日志位点 | | 4. Region B Leader 发起 Raft 提案: CommitMerge(Source: Region A) | | 5. Region B 多数派提交该日志: | | - 将本地 Key 范围原子扩展为: [a, z) | | - 物理接管 Region A 的全部历史数据并销毁 Region A 的 Raft 实例! | --------------------------------------------------------------------------1. 为什么跨 Raft 组的 Region 合并极其复杂在 Multi-Raft 体系中每一个 Region 是一个在物理上完全自治、拥有独立任期号Term与日志序列号Log Index的孤立宇宙Region A 和 Region B 可能由完全不同的物理节点副本构成Region A 的 Leader 根本无法直接向 Region B 的状态机写入日志如果 Region A 在合并中途突然发生 Leader 切换、或者网络分区导致 Region A 又接收了新的客户端写入盲目将数据合并进 Region B 会直接导致数据覆盖与幻读2. 两阶段合并Commit-Merge的严密状态机工业级 Multi-Raft如 TiKV通过严格的两阶段协议来保证合并的绝对安全性第一阶段源 Region 冻结PrepareMerge全局调度中心PD向源分片Region A发送合并调度指令Region A的 Leader 发起一条内部 Raft 日志AdminCmd::PrepareMerge { target_region_id: Region B, min_index }状态机冻结与 Epoch 递增当该日志在Region A内部达成多数派 Commit 并 Apply 时Region A将本地状态标记为Merging永久拒绝后续所有客户端的读写请求将Region A的epoch.version递增确保所有持老路由的客户端在访问时立刻被拦截。第二阶段目标 Region 接管与原子扩容CommitMergeRegion A向Region B发起跨分片内部 RPC告知其Region A已完全冻结当前日志最大 Index 为 $I_A$Region B的 Leader 检查自身 Key 区间与Region A是否严格物理连续例如Region A.end_key Region B.start_keyRegion B发起 Raft 提案AdminCmd::CommitMerge { source_region: Region A }原子合并生效当该日志在Region B内部被多数派 Commit 并 Apply 时Region B原子地将自身的start_key修改为Region A.start_key范围合并为[a, z)将Region B的epoch.version递增本地存储引擎正式将原属于Region A的数据纳入Region B的管理生命周期并在后台异步销毁Region A的 Raft 运行时。3. 合并中途遭遇异常的自愈与回滚Rollback如果在第一阶段PrepareMerge成功后目标Region B突然发生物理宕机或网络永久隔离导致第二阶段迟迟无法推进Region A维护一个超时定时器超时后Region A可以通过向自身发起一条AdminCmd::RollbackMergeRaft 日志解冻本地状态机并恢复正常读写避免分片陷入永久死锁。用严密的两阶段状态机跨越独立共识组的鸿沟让成千上万个动态分片在收缩与合并中始终保持毫厘不差的一致性这是现代分布式存储架构的至高工程艺术。