4、Raft安全性:选举限制、日志提交规则、Leader完整性保证、状态机安全

Raft 的安全性(Safety)是保证分布式一致性正确性的核心约束。在 etcd 的压测场景中,安全性问题往往表现为:Leader 频繁切换导致日志覆盖、已提交日志被回滚、状态机应用了不一致的日志条目。本节从四个维度拆解 Raft 的安全机制,并给出压测中可能触发的安全性风险点。

4.1 选举限制(Election Restriction)

Raft 通过 选举限制 确保只有拥有最新日志的节点才能成为 Leader。这一机制防止了日志回滚(Log Rollback),是 Raft 安全性的第一道防线。

选举限制的核心规则:

  • RequestVote RPC 中的日志比较:Candidate 在发起选举时,会在请求中携带自己最后一条日志的 term 和 index。
  • 投票者判断逻辑:投票者(Follower)只有在自己的日志比 Candidate 更新时,才会拒绝投票;否则投票给 Candidate。
  • 日志新旧判定:先比较 term,term 更大的日志更新;若 term 相同,则比较 index,index 更大的日志更新。
压测启示: 在 etcd 压测中,如果网络分区频繁发生,落后节点可能赢得选举。此时该节点成为 Leader 后,会强制覆盖其他节点的日志,导致已提交的写入丢失。压测时应关注 leader_changes_seen_total 指标,若 Leader 切换过于频繁,安全性风险显著上升。
选举限制:日志比较流程 Candidate term=5, index=12 Follower term=5, index=10 RequestVote(term=5, index=12) 日志比较结果 Candidate.index(12) > Follower.index(10) → 投票给 Candidate 反例:拒绝投票 若 Follower.index=15 → 拒绝投票,防止日志回滚

4.2 日志提交规则(Log Commitment Rule)

Raft 规定:Leader 只能提交当前任期(current term)的日志条目。这一规则防止了已提交日志被后续 Leader 覆盖。

日志提交规则详解:

场景 规则 安全性含义
Leader 提交自己任期的日志 当日志复制到大多数节点时,Leader 更新 commitIndex 该日志条目最终会被状态机应用,不会回滚
Leader 提交前任期的日志 不允许直接提交;必须通过提交当前任期的一条日志来间接提交 防止前任期的日志在未确认多数复制的情况下被提交
新 Leader 上任后 立即追加一条当前任期的空日志(no-op entry) 通过提交 no-op 来间接提交所有前任期的未提交日志
压测陷阱: 在 etcd 压测中,如果压测工具在 Leader 切换后立即发送写入请求,新 Leader 可能尚未完成 no-op 日志的提交。此时 commitIndex 可能落后于 lastApplied,导致读取到旧数据。压测时应等待 etcd_server_leader_changes_seen_total 稳定后再发起写入。

4.3 Leader 完整性保证(Leader Completeness)

Leader 完整性保证是 Raft 安全性的核心定理:一旦一个日志条目在某个 term 被提交,它就会出现在所有未来 Leader 的日志中。这个性质通过选举限制和日志提交规则共同保证。

完整性保证的证明逻辑:

  1. 提交定义:日志条目在 term T 被提交,意味着它被复制到了大多数节点。
  2. 选举限制:任何后续 term 的 Leader 必须获得大多数节点的投票,而大多数节点中至少有一个节点包含该已提交日志。
  3. 日志传递:新 Leader 通过 AppendEntries RPC 将日志复制到所有 Follower,确保已提交日志不会丢失。
压测指标关联: 监控 etcd_server_has_leader 和 etcd_server_leader_changes_seen_total。如果 Leader 切换后,某个节点的 raft_log_index 出现回退,说明完整性保证被破坏,需要立即排查。
Leader 完整性保证:日志传递链 节点 A (Leader) term=3, index=10 节点 B (新 Leader) term=4, index=10 节点 C (Follower) term=4, index=8 日志传递 index=10 日志复制 index=10 完整性保证的关键路径 1. 节点 A 在 term=3 提交 index=10,复制到大多数节点 2. 节点 B 赢得选举(term=4),其日志必须包含 index=10 3. 节点 B 将 index=10 复制给节点 C,保证日志不丢失

4.4 状态机安全(State Machine Safety)

状态机安全保证:所有节点以相同的顺序应用相同的日志条目。这是 Raft 线性一致性的基础。

状态机安全的实现机制:

  • 日志顺序性:日志条目在 Raft 集群中按 term 和 index 严格排序,所有节点看到的日志序列一致。
  • 提交即应用:节点只有在日志条目被提交(commitIndex 更新)后,才会将其应用到状态机。
  • 幂等性:状态机应用日志的操作必须是幂等的,防止重复应用导致状态不一致。
etcd 实践: etcd 的状态机是 BoltDB(或 bbolt),它通过 MVCC 和事务保证状态机安全。压测中如果出现 mvcc: database space exceeded 错误,说明状态机写入压力过大,需要调整 --quota-backend-bytes 参数。

4.5 安全性总结与压测检查清单

安全性维度 核心机制 压测检查项 关键指标
选举限制 日志比较(term, index) 网络分区下 Leader 选举是否安全 leader_changes_seen_total
日志提交规则 只提交当前任期日志 Leader 切换后 no-op 日志是否及时提交 raft_log_commit_index
Leader 完整性 已提交日志出现在所有未来 Leader 日志 index 是否出现回退 raft_log_index 单调性
状态机安全 顺序应用、幂等性 状态机应用是否一致 etcd_server_applied_index
压测红线: 如果压测过程中发现 raft_log_index 出现非单调递增(回退),或者 etcd_server_applied_index 与 raft_log_commit_index 差距持续扩大,说明 Raft 安全性可能被破坏。此时应立即停止压测,检查网络分区、磁盘 I/O 和节点时钟同步情况。