高可用的前提是复制

要在一台机器坏掉时数据不丢、服务不断,唯一的办法是把数据保存多份,并且让这些副本之间保持同步。问题在于:多副本之间如何达成一致?如何在某个副本失联时仍然安全地继续写入?

Raft 是这类问题的经典解法,它把一致性问题拆解为领导选举、日志复制、安全性约束三个相对独立的子问题。

复制组是怎么组织的

分布式存储通常不会把整库做成一个复制组,而是按数据范围切分成大量小复制组。以 TiKV 为例,数据被切分为 Region,每个 Region 就是一个独立的 Raft 复制组,拥有自己的副本集合与 Leader。

  • 副本数量可配置,常见为三副本或五副本;
  • 同一 Region 的多个副本会被尽量分散到不同节点、机架乃至机房;
  • 因为复制组数量多,单组故障只影响一小段数据范围,不会拖垮整个集群。

日志复制与多数派提交

写请求统一由某个副本处理,这个副本称为 Leader。它的处理流程是:

  1. 收到写请求后,把操作作为一条日志追加到本地日志序列;
  2. 并行把该日志复制给其他副本;
  3. 超过半数的副本确认已持久化该日志,Leader 才认为这条日志已提交;
  4. Leader 把提交结果返回客户端,并通知其他副本该日志已提交、可以应用。

「多数派」是这套机制安全性的核心。任意两个多数派必然存在交集,因此新选出的 Leader 一定包含所有已提交的日志,不会出现已确认的数据被覆盖的情况。

由此也能推出一个重要约束:副本数不能无限增加。副本越多,达成多数派所需的网络往返越多,写入延迟越高,而容错能力只与「可容忍失效副本数」有关,通常三副本已能容忍单副本故障。

Leader 选举与自动故障转移

当 Leader 所在节点故障或网络隔离时,其他副本经过一段选举超时后会发起选举:

  1. 候选者递增任期号并向其他副本请求投票;
  2. 获得多数派投票的候选者成为新 Leader;
  3. 新 Leader 立即开始接受写入并继续复制日志。

整个过程由系统自动完成,不需要人工干预。故障转移的耗时主要取决于选举超时配置与网络状况,通常在秒级。对业务而言,这段时间内涉及该 Region 的写入会短暂受阻或重试,读取在多数派仍可用时基本不受影响。

分区与负载均衡

除了容错,复制组还需要应对数据增长与负载不均:

  • 分裂:Region 增大到阈值后自动分裂成两个,使每个复制组保持合适的规模;
  • 调度:调度中心根据各节点负载,迁移副本与转移 Leader,避免个别节点过热;
  • 副本调整:可按需增加或减少某段数据的副本数,例如为冷数据降低副本以节省空间。

容灾拓扑的选择

副本放在哪里,直接决定容灾级别与写入延迟:

  1. 同机房三副本:延迟最低,可容忍单机故障,但机房级故障会整体不可用;
  2. 同城多机房:可容忍机房故障,写入延迟受同城网络影响较小;
  3. 两地多中心:可容忍城市级故障,但跨城复制会显著增加写入延迟,通常需要配合异步或特殊副本角色使用。

选择原则是先明确业务能承受多长的不可用与多少数据丢失,再倒推副本拓扑,而不是反过来追求最高容灾级别而牺牲性能。

Raft 相关机制
复制组每个数据分片(Region)独立构成一个 Raft 组,各自维护副本集与 Leader
写入路径Leader 追加日志 -> 并行复制 -> 多数派确认 -> 提交并返回客户端
故障转移Leader 失效后副本经过选举超时发起投票,多数派选出新 Leader,全程自动
规模控制分片达阈值自动分裂,调度中心按负载迁移副本与转移 Leader
拓扑取舍同机房延迟最低,同城与两地多中心容灾更强但写入延迟更高