目录

一、Raft基础

二、Leader选举流程

2.1 初始化时,所有follower都在等待成为candidate的场景

2.2 获得多数派投票成为leader

2.3 接收到leader的Append Entries消息(心跳包)

2.4 同时存在两个candidate,并且获得选票相同

三、日志复制过程

3.1 Leader发起request请求

3.2 leader节点发送日志条目到所有followers节点

3.3 心跳包传回Leader节点,Leader复制状态机执行日志条目中命令

3.3 Leader节点通知所有Follower节点可以执行命令


参考链接:

raft官网

https://raft.github.io/

raft动画

http://thesecretlivesofdata.com/raft/

raft视频讲解

https://www.bilibili.com/video/av21667358/

raft经典场景分析(图文并茂,生动形象)

https://zhuanlan.zhihu.com/p/27970722

分布式一致性算法:Raft 算法(译文)

http://linbingdong.com/2017/03/11/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%80%E8%87%B4%E6%80%A7%E7%AE%97%E6%B3%95%EF%BC%9ARaft%20%E7%AE%97%E6%B3%95%EF%BC%88Raft%20%E8%AE%BA%E6%96%87%E7%BF%BB%E8%AF%91%EF%BC%89/#5-4-1-%E9%80%89%E4%B8%BE%E9%99%90%E5%88%B6

一致性算法允许多台机器作为一个集群协同工作,并且在其中的某几台机器出故障时集群仍然能正常工作。 

正因为如此,一致性算法在建立可靠的大规模软件系统方面发挥了关键作用。 在过去十年中,Paxos 是一致性算法的主流,

大多数一致性算法的实现都是基于 Paxos 或受其影响,Paxos 已成为用于教授学生一致性相关知识的主要工具。

但不幸的是,Paxos 实在是太难以理解,我们开始着手寻找一个新的一致性算法,可以为系统开发和教学提供更好的帮助。 

下面就是我们的主角闪亮登场,Raft 的一致性算法

一、Raft基础

分为以下几点:

1.1 节点个数

一个 Raft 集群包含若干个服务器节点;通常是 5 个(奇数个),这样的系统可以容忍 2 个节点的失效。

1.2  节点状态

每个节点有三个状态,他们会在这三个状态之间进行变换。客户端只能从主节点写数据,从节点里读数据。

现在我们将leader、follower 或者 candidate三种状态,类比现实世界中选举流程中的角色

leader对应“国会议员”,当获取多数派的投票后,candidate会晋升成leader状态

follower对应“老百姓”,有

candidate对应“候选人”,

在正常情况下,集群中只有一个 leader ,并且其他的节点全部都是 follower

Follower 都是被动的:他们不会发送任何请求,只是简单的响应来自 leader 和 candidate 的请求

Leader 处理所有的客户端请求(如果一个客户端和 follower 通信,follower 会将请求重定向给 leader)。

二、Leader选举流程

所有服务器节点初始状态都是Follwer状态,一个服务器节点只要能从 leader 或 candidate 处接收到有效的 RPC 就一直保持 follower 状态。

有两种超时时间timeout来控制选举,

一种是election timeout,是节点从followers状态转换到candidate状态的等待时间,随机初始化值为150ms ~ 300ms

一种是heartbeat timeout,用于Leader和follower之间的保活。

2.1 初始化时,所有follower都在等待成为candidate的场景

当某个follower的election timeout先到达后,follower 先增加自己的当前任期号并且转换到 candidate 状态

然后投票给自己并且并行地向集群中的其他服务器节点发送 RequestVote RPC(让其他服务器节点投票给它)

2.2 获得多数派投票成为leader

当一个 candidate节点 获得多数派的followers的投票,它就赢得了这次选举并成为 leader 。然后它会follower节点发送心跳消息来确定自己的地位并阻止新的选举。 

2.3 接收到leader的Append Entries消息(心跳包)

在等待投票期间,candidate 可能会收到另一个声称自己是 leader 的服务器节点发来的 AppendEntries RPC 。如果这个 leader 的任期号(包含在RPC中)不小于 candidate 当前的任期号,那么 candidate 会承认该 leader 的合法地位并回到 follower 状态。 如果 RPC 中的任期号比自己的小,那么 candidate 就会拒绝这次的 RPC 并且继续保持 candidate 状态。

2.4 同时存在两个candidate,并且获得选票相同

raft Java 实现框架 raft 教程_通俗易懂

图中,A和D同时成为candidate

如果有两个 follower 同时成为 candidate ,那么选票可能会被瓜分以至于没有 candidate 赢得过半的投票。

当这种情况发生时,每一个候选人都会超时,然后通过增加当前任期号来开始一轮新的选举。然而,如果没有其他机制的话,该情况可能会无限重复。

Raft 算法使用随机选举超时时间的方法来解决这个问题,每个 candidate 在开始一次选举的时候会重置一个随机的选举超时时间,然后一直等待直到选举超时;这样减小了在新的选举中再次发生选票瓜分情况的可能性。

raft Java 实现框架 raft 教程_通俗易懂_02

D节点由于随机的超时时间比A节点的超时时间短,先达到超时状态,获得大多数的选票成为Leader。

三、日志复制过程

3.1 Leader发起request请求

raft Java 实现框架 raft 教程_教程_03

request请求后在leader节点写入日志条目,此时leader节点为uncommited状态,复制状态机并没有执行命令

3.2 leader节点发送日志条目到所有followers节点

raft Java 实现框架 raft 教程_图文教程_04

Leader节点并行的向集群中所有followers节点发送Append Entries RPC 请求(简称“心跳包”),子节点复制日志条目后,由于心跳包还没传回Leader节点,Leader节点仍然为uncommitted状态

3.3 心跳包传回Leader节点,Leader复制状态机执行日志条目中命令

raft Java 实现框架 raft 教程_raft Java 实现框架_05

心跳包传回Leader节点,Leader得知大多数follower服务器已经将该命令写入日志条目中,leader 会应用该条目到它的状态机中(状态机执行该指令),然后返回结果给客户端。

3.3 Leader节点通知所有Follower节点可以执行命令

raft Java 实现框架 raft 教程_raft Java 实现框架_06

当一条日志是commited时,Leader才会将它应用到状态机中。Raft保证一条commited的log entry已经持久化了并且会被所有的节点执行。