Raft算法

转载自:https://www.jianshu.com/p/8e4bbe7e276c

  
  首先介绍下分布式共识算法。分布式共识算法是指:多个参与者 针对 某一件事 达成完全 一致 :一件事,一个结论;已达成一致的结论,不可推翻。

  目前分布式共识算法有如下:
  Paxos:被认为是分布式共识算法的根本,其他都是其变种,但是 Paxos 论文中只给出了单个提案的过程,并没有给出复制状态机中需要的 multi-paxos 的相关细节的描述,实现 Paxos 具有很高的工程复杂度(如多点可写,允许日志空洞等)。
  Zab:被应用在 Zookeeper 中,业界使用广泛,但没有抽象成通用的 library。
  Raft:以容易理解著称,业界也涌现出很多 Raft 实现,比如大名鼎鼎的 etcd, braft, tikv 等。

什么是 Raft?
  Raft 是一种更易于理解的分布式共识算法,核心协议本质上还是师承 Paxos 的精髓,不同的是依靠 Raft 模块化的拆分以及更加简化的设计,Raft 协议相对更容易实现。
  模块化的拆分主要体现在:Raft 把一致性协议划分为 Leader 选举、Membership 变更、日志复制、Snapshot 等几个几乎完全解耦的模块。
  更加简化的设计则体现在:Raft不允许类似 Paxos 中的乱序提交、简化系统中的角色状态(只有 Leader、Follower、Candidate 三种角色)、限制仅 Leader 可写入、使用随机化的超时时间来设计 Leader Election 等等。
  Raft算法中系统必须存在且同一时刻只能有一个 Leader,只有 Leader 可以接受 Clients 发过来的请求;Leader 负责主动与所有 Followers 通信,负责将“提案”发送给所有 Followers,同时收集多数派的 Followers 应答;Leader 还需向所有 Followers 主动发送心跳维持领导地位(保持存在感)。

  

1. Raft 节点状态

  每个节点有三种状态:Follower,Candidate,Leader,状态之间是互相转换的。
  每个节点上都有一个倒计时器 (Election Timeout),时间随机在 150ms ~300ms 之间。有几种情况会重设 Timeout:
  1.收到选举的请求
  2.收到 Leader 的 Heartbeat

  在 Raft 运行过程中,最主要进行两个活动:
  1.选主 Leader Election
  2.复制日志 Log Replication

  

2.选主 Leader Election

2.1 正常情况下选主

  假设现在有如图5个节点,5个节点一开始的状态都是 Follower。在一个节点election timeout到期后,这个节点的状态变成 Candidate 开始选举,它会会先投自己一票,然后向整个集群发起选举请求 (RequestVote)
Raft算法
  其他四个节点都返回成功,这个节点的状态由 Candidate 变成了 Leader,并在每个一小段时间后,就给所有的 Follower 发送一个 Heartbeat 以保持所有节点的状态,Follower 收到 Leader 的 Heartbeat 后重设 Timeout。心跳检测时间很短,要远远小于选举超时时间election timout。
Raft算法
  这是最简单的选主情况,只要有超过一半的节点投支持票了,Candidate 才会被选举为 Leader,5个节点的情况下,3个节点 (包括 Candidate 本身) 投了支持就行。
  除此之外,每个节点中还有一个字段,叫term,意思就是任期,这个term是一个全局的、连续递增的整数,每进行一次选举,term就会加一,如果candidate赢得选举,它会当leader直到此次任期结束。

2.2 Leader出故障情况下的选主

  一开始已经有一个 Leader,所有节点正常运行。Leader 出故障挂掉了,其他四个 Follower 将进行重新选主。
  4个节点的选主过程和5个节点的类似,假设在选出一个新的 Leader 后,原来的 Leader 恢复了又重新加入了,这个时候怎么处理?在 Raft 里,第几轮选举是有记录的,重新加入的 Leader 是第一轮选举 (Term 1) 选出来的,而现在的 Leader 则是 Term 2,所有原来的 Leader 会自觉降级为 Follower。

2.3 多个 Candidate 情况下的选主

  假设一开始有4个节点,都还是 Follower。这时,有两个 Follower 同时 Timeout,都变成了 Candidate 开始选举,分别给 Follower 发送了投票请求。两个 Follower 分别返回了ok,这时两个 Candidate 都只有2票,要3票才能被选成 Leader。两个 Candidate 会分别给另外一个还没有给自己投票的 Follower 发送投票请求。但是因为 Follower 在这一轮选举中,都已经投完票了,所以都拒绝了他们的请求。所以在 Term 2 没有 Leader 被选出来。
  这时,两个节点的状态是 Candidate,两个是 Follower,但是他们的倒计时器仍然在运行,最先 Timeout 的那个节点会进行发起新一轮 Term 3 的投票。两个 Follower 在 Term 3 还没投过票,所以返回 OK,这时 Candidate 一共有三票,被选为了 Leader。
  如果 Leader Heartbeat 的时间晚于另外一个 Candidate timeout 的时间,另外一个 Candidate 仍然会发送选举请求。两个 Follower 已经投完票了,拒绝了这个 Candidate 的投票请求。Leader 进行 Heartbeat, Candidate 收到后状态自动转为 Follower,完成选主。

  

3. 复制日志 Log Replication

3.1 正常情况下复制日志

  Raft 在实际应用场景中的一致性更多的是体现在不同节点之间的数据一致性,客户端发送请求到任何一个节点都能收到一致的返回,当一个节点出故障后,其他节点仍然能以已有的数据正常进行。在选主之后的复制日志就是为了达到这个目的。
  Raft算法中无论读和写都会由leader节点来处理。读也由leader来处理,leader拿到请求后,再决定由哪一个节点来处理,要么将请求分发,要么自己处理;即使client端请求的是follower节点,Follower节点也会现将请求信息转给leader,再由leader决定由哪个节点来处理。

  一开始,Leader 和 两个 Follower 都没有任何数据。客户端发送请求给 Leader,储存数据 “sally”,Leader 先将数据写在本地日志,这时候数据还是 Uncommitted (还没最终确认)。
  Leader 给两个 Follower 发送 AppendEntries 请求,数据在 Follower 上没有冲突,则将数据暂时写在本地日志,Follower 的数据也还是 Uncommitted。
  Follower将数据写到本地后,返回 OK。Leader 收到后成功返回,只要收到的成功返回的数量超过半数 (包含Leader),Leader 将数据 “sally” 的状态改成 Committed。( 这个时候 Leader 就可以返回给客户端了)。
  Leader 再次给 Follower 发送 AppendEntries 请求(相当于commit的通知),收到请求后,Follower 将本地日志里 Uncommitted 数据改成 Committed。这样就完成了一整个复制日志的过程,三个节点的数据是一致的。

3.2 Network Partition 情况下进行复制日志

  在 Network Partition 的情况下,部分节点之间没办法互相通信,Raft 也能保证在这种情况下数据的一致性。
  假设,一开始有 5 个节点处于同一网络状态下。Network Partition 将节点分成两边,一边有两个节点,一边三个节点。
  两个节点这边已经有 Leader 了,来自客户端的数据 “bob” 通过 Leader 同步到 Follower。因为只有两个节点,少于3个节点,所以 “bob” 的状态仍是 Uncommitted。所以在这里,服务器会返回错误给客户端。
  另外一个 Partition 有三个节点,进行重新选主。客户端数据 “tom” 发到新的 Leader,通过和上节网络状态下相似的过程,同步到另外两个 Follower。因为这个 Partition 有3个节点,超过半数,所以数据 “tom” 都 Commit 了。
  网络状态恢复,5个节点再次处于同一个网络状态下。但是这里出现了数据冲突 “bob" 和 “tom"。
  三个节点的 Leader 广播 AppendEntries,两个节点 Partition 的 Leader 自动降级为 Follower,因为这个 Partition 的数据 “bob” 没有 Commit,返回给客户端的是错误,客户端知道请求没有成功,所以 Follower 在收到 AppendEntries 请求时,可以把 “bob“ 删除,然后同步 ”tom”,通过这么一个过程,就完成了在 Network Partition 情况下的复制日志,保证了数据的一致性。

  
可以参考:
  图解Raft:https://blog.****.net/i6448038/article/details/85525040
  Raft 原理动画:http://thesecretlivesofdata.com/raft/