raft protocol
Raft协议模拟运行(包含多种场景)
初始状态
- 集群节点:3个节点(A、B、C),初始Term为1。
- 角色分配:
- A为Leader,B、C为Follower。
- 日志状态:所有节点日志为空。
场景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消息,提交日志到状态机。
- Leader A:
最终状态:所有节点日志为[索引1: Term1, SET x=1]
,数据一致。
场景2:Leader崩溃与重新选举
- Leader A崩溃(Term1未结束)。
- Followers B、C心跳超时(B的超时先触发)。
- B转为Candidate(Term=2),发起选举请求:
- 发送
RequestVote
(Term=2,最新日志索引=1,Term=1)。
- 发送
- C收到请求:
- 检查B的日志完整性(与自身一致),投票给B。
- B获得2票(自身+C),成为新Leader(Term=2)。
- B转为Candidate(Term=2),发起选举请求:
新状态:
- Leader B(Term=2),Follower C(Term=2),A宕机。
场景3:新Leader处理写入与日志冲突
**客户端请求写入
SET x=2
**(发送到Leader B)。- Leader B:
- 追加日志(索引2,Term2),发送
AppendEntries
给C。 - C确认,日志提交并响应客户端成功。
- 追加日志(索引2,Term2),发送
- 日志状态:B、C的日志为
[索引1: Term1, 索引2: Term2]
。
- Leader B:
旧Leader A恢复并尝试写入(仍认为自己是Term1的Leader):
- A发送
AppendEntries
(索引1,Term1)给B、C。 - B、C发现Term1 < 当前Term2,拒绝请求并返回Term=2。
- A收到响应后降级为Follower,更新Term为2。
- A发送
最终状态:
- Leader B(Term=2),Followers A、C(Term=2),所有节点日志一致。
场景4:网络分区与脑裂规避
网络分区:
- 分区1:A、B(假设Leader B在分区1)。
- 分区2:C(独立分区)。
**分区1的Leader B接收写入
SET x=3
**:- 发送
AppendEntries
给A,因分区1有2/3节点,日志提交成功。 - 日志状态:B、A的日志为
[索引1: Term1, 索引2: Term2, 索引3: Term2]
(已提交)。
- 发送
分区2的C心跳超时(试图选举新Leader):
- C转为Candidate(Term=3),但因无法获得半数以上投票,选举失败。
网络恢复:
- C收到B的心跳(Term=2),发现Term较低,拒绝并返回Term=3。
- B收到Term=3响应后降级为Follower,集群触发新选举。
- 新选举:A、B、C中日志最全的节点(B或 C)成为Leader。
关键结果:
- 分区期间只有多数派分区(A、B)可提交日志,C的未提交日志被丢弃。
- 网络恢复后,日志通过新Leader同步,C覆盖本地日志以确保一致。
场景5:日志冲突与同步修复
初始状态:
- Leader B(Term=3),日志为
[索引1: Term1, 索引2: Term2, 索引3: Term3]
(已提交)。 - Follower C因网络延迟,日志停留在
[索引1: Term1, 索引2: Term2]
。
- Leader B(Term=3),日志为
Leader B发送
AppendEntries
(索引3,Term3)给C:- 请求包含
prevLogIndex=2
,prevLogTerm=Term2
。 - C检查本地日志:索引2的Term=2匹配,接受新日志(索引3)。
- 请求包含
C日志修复完成:
- 所有节点日志一致为
[索引1: Term1, 索引2: Term2, 索引3: Term3]
。
- 所有节点日志一致为
场景6:快照与日志压缩
- Leader生成快照(Snapshot):
- 压缩索引1-3的日志,保存状态机状态
x=3
。
- 压缩索引1-3的日志,保存状态机状态
- Follower C重启后日志落后:
- Leader发送快照+最新日志(索引4+)给C,避免全量日志传输。
优势:减少同步数据量,加速故障恢复。
总结
- 一致性保证:通过选举限制、日志匹配和Leader完整性,Raft规避脑裂和数据不一致。
- 容错能力:容忍半数节点故障,自动恢复日志同步。
- 工程实践:快照、心跳优化、预投票等机制增强鲁棒性。
示意图:
1 |
|
raft protocol
https://yintel12138.github.io/2025/02/12/raft-protocol/