raft protocol


Raft协议模拟运行(包含多种场景)


初始状态

  • 集群节点:3个节点(A、B、C),初始Term为1。
  • 角色分配
    • A为Leader,B、C为Follower。
  • 日志状态:所有节点日志为空。

场景1:正常写入流程

  1. 客户端请求写入SET x=1
    • Leader A
      • 将操作追加到本地日志(索引1,Term1)。
      • 发送AppendEntries请求(索引1,Term1)给B、C。
    • Followers B、C
      • 确认日志持久化,返回成功。
    • Leader A
      • 收到2个确认(含自身,共3节点),标记日志为已提交(Committed)。
      • 更新状态机,响应客户端成功。
    • Followers B、C
      • 在下次心跳中收到Commit消息,提交日志到状态机。

最终状态:所有节点日志为[索引1: Term1, SET x=1],数据一致。


场景2:Leader崩溃与重新选举

  1. Leader A崩溃(Term1未结束)。
  2. Followers B、C心跳超时(B的超时先触发)。
    • B转为Candidate(Term=2),发起选举请求:
      • 发送RequestVote(Term=2,最新日志索引=1,Term=1)。
    • C收到请求
      • 检查B的日志完整性(与自身一致),投票给B。
    • B获得2票(自身+C),成为新Leader(Term=2)。

新状态

  • Leader B(Term=2),Follower C(Term=2),A宕机。

场景3:新Leader处理写入与日志冲突

  1. **客户端请求写入SET x=2**(发送到Leader B)。

    • Leader B
      • 追加日志(索引2,Term2),发送AppendEntries给C。
      • C确认,日志提交并响应客户端成功。
    • 日志状态:B、C的日志为[索引1: Term1, 索引2: Term2]
  2. 旧Leader A恢复并尝试写入(仍认为自己是Term1的Leader):

    • A发送AppendEntries(索引1,Term1)给B、C。
    • B、C发现Term1 < 当前Term2,拒绝请求并返回Term=2。
    • A收到响应后降级为Follower,更新Term为2。

最终状态

  • Leader B(Term=2),Followers A、C(Term=2),所有节点日志一致。

场景4:网络分区与脑裂规避

  1. 网络分区

    • 分区1:A、B(假设Leader B在分区1)。
    • 分区2:C(独立分区)。
  2. **分区1的Leader B接收写入SET x=3**:

    • 发送AppendEntries给A,因分区1有2/3节点,日志提交成功。
    • 日志状态:B、A的日志为[索引1: Term1, 索引2: Term2, 索引3: Term2](已提交)。
  3. 分区2的C心跳超时(试图选举新Leader):

    • C转为Candidate(Term=3),但因无法获得半数以上投票,选举失败。
  4. 网络恢复

    • C收到B的心跳(Term=2),发现Term较低,拒绝并返回Term=3。
    • B收到Term=3响应后降级为Follower,集群触发新选举。
    • 新选举:A、B、C中日志最全的节点(B或 C)成为Leader。

关键结果

  • 分区期间只有多数派分区(A、B)可提交日志,C的未提交日志被丢弃。
  • 网络恢复后,日志通过新Leader同步,C覆盖本地日志以确保一致。

场景5:日志冲突与同步修复

  1. 初始状态

    • Leader B(Term=3),日志为[索引1: Term1, 索引2: Term2, 索引3: Term3](已提交)。
    • Follower C因网络延迟,日志停留在[索引1: Term1, 索引2: Term2]
  2. Leader B发送AppendEntries(索引3,Term3)给C

    • 请求包含prevLogIndex=2prevLogTerm=Term2
    • C检查本地日志:索引2的Term=2匹配,接受新日志(索引3)。
  3. C日志修复完成

    • 所有节点日志一致为[索引1: Term1, 索引2: Term2, 索引3: Term3]

场景6:快照与日志压缩

  1. Leader生成快照(Snapshot):
    • 压缩索引1-3的日志,保存状态机状态x=3
  2. Follower C重启后日志落后
    • Leader发送快照+最新日志(索引4+)给C,避免全量日志传输。

优势:减少同步数据量,加速故障恢复。


总结

  • 一致性保证:通过选举限制、日志匹配和Leader完整性,Raft规避脑裂和数据不一致。
  • 容错能力:容忍半数节点故障,自动恢复日志同步。
  • 工程实践:快照、心跳优化、预投票等机制增强鲁棒性。

示意图

1
[正常写入][Leader崩溃][选举新Leader][日志修复][分区恢复同步]

raft protocol
https://yintel12138.github.io/2025/02/12/raft-protocol/
作者
Yintel
发布于
2025年2月12日
许可协议