Raft协议详解
2026/4/17 20:31:54 网站建设 项目流程

一、Raft协议基本流程

1、示例动画

先来看下Raft协议到底是个什么样子的。网上有个动画文稿,是对Raft算法最生动形象的描述。地址: http://thesecretlivesofdata.com/raft/

从这个动画中可以看到, Raft协议是分为两个阶段工作的:Election选举和Log Replicaion日志同步。也就是说Raft要解决的其实是两个事情,一个是集群中选举产生主节点。另一个是在集群内进行数据同步。

2、工作流程

Raft算法的基本工作流程是这样的:

这里重点是需要理解Log日志和State Machine状态机。Log日志就是保存在Server上的操作日志,其中每个条目称为Entry。Entry中的操作,最终都会落地到StateMachine中。Raft算法的核心就是要保证所有节点上的Entry顺序一致。

注意:是保证Entry顺序一致,而不是保证Entry不丢失,这是两个概念。

1、多个Server基于他的一致性协议,会共同选举产生一个 Leader,负责响应客户端的请求。

2、Leader 通过一致性协议,将客户端的指令转发到集群所有节点上。

3、每个节点将客户端的指令以 Entry 的形式保存到自己的 Log 日志当中。此时 Entry 是uncommited状态。

4、当有多数节点共同保存了 Entry 后,就可以将 Entry 中的客户端执行,提交到State Machine 状态机中。此时 Entry 更新为commited状态。

3、节点的三种状态

为此,Raft协议给每个节点设定了三种不同的状态,Leader,Follower和Candidate。

  • Leader :

1、选举产⽣。多数派决定。

2、向 Follower 节点发送⼼跳,Follower 收到⼼跳就不会竞选Leader。

3、响应客户端请求。集群内所有的数据变化都从 Leader 开始。

4、向 Follower 同步操作⽇志。 具体实现时,有的产品会让发到 Follower 上的请求转发到 Leader 上去。 也有的直接拒绝

  • Follower:

1、参与选举投票。

2、同步 Leader 上的数据。

3、接收 Follower 的⼼跳。如果 Follower ⻓期没有发送⼼跳,就转为 Candidate,竞选 Leader。

  • Candidate:

没有 Leader 时,发起投票,竞选 Leader。

4、节点状态变化

Raft协议为了保证同一时刻,集群当中最多只会有一个主节点,防止脑裂问题,还会增加一个Term任期的概念。

时间被划分为多个任期。每个任期都以选举开始。选举成功后,由一名Leader管理集群,直到任期结束。有些选举失败了,没有选举出Leader,那就进入下一个任期,开始下一次选举。

从CAP理论的角度分析,Raft优先保证的是CP,而放弃了A。与之形成对比的是Eureka,保证AP。

他们的状态变化过程是这样的:

1、所有节点启动时都从 Follower 状态开始。

2、每个Follower 设定了⼀个选举过期时间Election Timeout 。Follower持续等待 Leader 的⼼跳请求。如果超过选举过期时间,就转为 Candidate,向其他节点发起投票,竞选 Leader。为了防⽌所有节点在同⼀时间过期,这个选举过期时间通常会设定为⼀个随机值,⼀般在 150ms到 300ms之间。

3、Candidate 开始新⼀个任期的选举。每个 Candidate 会投⾃⼰⼀票,然后向其他节点发起投票 RPC 请求。然后等待其他节点返回投票结果。等待时⻓也是Election Timeout。

4、每个节点在每⼀个任期内有⼀次投票的资格。他们会响应 Candidate 的投票 RPC 请求。按照⼀定的规则进⾏投票。返回⽀持 或者 不⽀持。

5、Candidate 收到其他节点的投票 RPC 响应之后,会重置他的 Election Timeout,继续等待其他响应。⼀旦某⼀个 Candidate 接收到了超过集群⼀半节点的投票同意结果后,就会转为 Leader 节点。并开始向其他节点发送⼼跳 RPC 请求。确认⾃⼰的 Leader 地位。

6、其他节点接收到 Leader 的⼼跳后,就会乖乖的转为 Follower 状态。 Candidate 也会转为 Follower 。然后等待从 Leader 同步⽇志。直到 Leader 节点⼼跳超时或者服务宕机,再触发下⼀轮选举,进⼊下⼀个 Term任期。

二、Raft协议实现机制

接下来思考下Raft算法要如何实现这些流程呢?这里我们主要分析每个节点要保存哪些数据,然后RPC请求要传递哪些数据。

这里简单总结Raft算法的基础数据结构:

首先是数据:

所有节点都需要的信息

  • currentTerm: 服务器当前的任期
  • votedFor:当前任期内投票给了谁。
  • log[]:日志条目Entry。每个 Entry 要包含Command:客户端指令,term:任期,idx:Entry 的偏移量。
  • commitIndex:标记为commited的 Entry 的索引。记录消息同步的进度。
  • lastApplied:已执行完 Command的 Entry 索引。 记录往状态机提交的进度。lastApplied<=commitIndex。 这两个主要是提交到状态机需要

Leader 上的特有参数

  • nextIndex[] : 给每个 Follower 同步到了哪一条 Entry。记录与follower 的同步进度。
  • matchIndex[]:给每个 Follower 已经复制到了哪一条 Entry。主要是要记录有哪些 Entry 发给 Follower,正在等待 Follower 确认中。

然后看RPC 请求,最为核心的有三个。第一个是 Candidate投票的 RPC 请求。第二个是 Leader 发送的心跳请求。第三个是Leader 发送的日志同步请求。

对于投票请求,主要请求参数

  • term : 当前任期
  • candidateId: 投票的候选人 ID。
  • lastLogIndex:候选人的最后日志Entry 索引。
  • last logo term:候选人最后日志条目的任期号。

前两个参数是必须的。后两个参数主要是当主从发生切换时,可以用来找出最新的Candidate。

主要响应参数:

  • term : 当前任期号
  • voteGranted:投票结果。是否支持当前 Candidate 当选为 Leader。

**对于后两个请求,都是有 Leader 往 Follower 发送。**其实可以合并为一种请求。心跳请求不带日志条目,而同步日志请求带日志条目。Follower 只要判断下有没有日志条目就可以区分是哪种请求。

主要请求参数:

  • term:当前领导者的任期
  • leaderId:当前领导者的 ID。
  • entries[]:要同步的日志条目。心跳请求就传空。同步消息请求则可以支持批量同步。
  • leaderCommit:领导者已知已提交的最高的日志条目的索引。主要是 Follower 要知道新的条目是要从哪里开始同步。
  • 为了安全起见,论文中还建议将上一条 Entry 的Index 以及 Term 发送过来。主要还是用来协助 Follower 定位 Entry

主要响应参数:

  • term 当前任期。
  • success: 响应是否成功。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询