Raft论文学习笔记

先附上论文连接  https://pdos.csail.mit.edu/6.824/papers/raft-extended.pdfgit

最近在自学MIT的6.824分布式课程,找到两个比较好的github:MIT课程《Distributed Systems 》学习和翻译 和 https://github.com/chaozh/MIT-6.824-2017github

6.824的Lab 2 就是实现Raft算法。Raft是一种分布式一致性算法,提供了和paxos相同的功能和性能,但比paxos要容易理解不少。算法

一:Raft的一些概念安全

为了提高可理解性,Raft 将一致性算法分解成了几个部分:、服务器

1)Leader选举:当以前的Leader宕机的时候,要选出新的Leader并发

2)日志复制:Leader从客户端接收日志而后复制到集群中的其它节点,而且要使其它节点的日志保持和本身相同分布式

3)安全性:若是有任何的服务器节点已经commit一个日志条目到它的状态机中,那么其它服务器节点不能在同一个日志索引位置commit一个不一样的指令。性能

Raft将系统中的角色分为领导者(Leader)、跟随者(Follower)和候选人(Candidate):学习

Leader:一般状况下系统中只有一个Leader,其它服务器节点都是Follower。Leader负责接受客户端的请求并把日志同步到Follower。Raft 中日志条目都遵循着从Leader发送给其它节点这一个方向,这也是Raft追求简单易懂的体现,像Viewstamped Replication和Zookeeper日志条目的流动都是双向的,致使机制比较复杂。spa

Follower:接受并持久化Leader同步的日志,在Leader告之日志能够提交以后,提交日志。

Candidate:Leader选举过程当中的临时角色。

这三种角色的转换以下图:

 

Follower只响应来自其余服务器的请求。若是Follower接收不到消息,那么它就会变成Candidate并发起一次选举。得到集群中大多数选票的Candidate将成为Leader。Leader在宕机以前一直都会是Leader。

Raft算法将时间分为一个个的任期(term),每个term的开始都是Leader选举。在成功选举Leader以后,Leader会在整个term内管理整个集群。若是Leader选举失败,该term就会由于没有Leader而结束,在下一个term继续选Leader。

 二:Leader选举

  Raft 使用一种心跳机制来触发领导人选举。在初始状态,服务器节点都是Follower,若是Follower在一段时间(election timeout)内没有接收到Leader的心跳,则认为Leader挂了。此时Follower会将term加1,并转换为Candidate状态。而后Follower会向集群中其它服务器节点发送RequestVote消息请求其它节点投票给本身。一个节点收到RequestVote 消息后经过比较两份日志中最后一条日志条目的索引值和term得出谁的日志比较新。若是本节点的日志比较新,则会拒绝掉该投票请求,不然同意。当Candidate获得大多数节点的同意后,则此Candidate会成为Leader,并不断发送心跳给其它节点,以维持其Leader地位。
  这种选举方法保证了Leader有着最新的日志,这样就能保证日志条目都遵循着从Leader发送给其它节点这一个方向,使Raft更容易理解。

  若是选票被瓜分,会致使全部Candidate都没法获得大多数节点的同意票,会致使选举失败。在下一轮选举中,一样也会出现这种选票瓜分的状况。为了不出现这种问题,raft将选举超时时间随机化,这样就不会出现多个Candidate同时选举超时,再同时发起选举的状况。这样在第一个选举超时的Candidate会有最大的term,发送RequestVote从而成为Leader。

3、日志复制

  Leader被选举出来后,就能够接受客户端的请求了。客户端的每一个请求都包含一条被Replicated State Matchine执行的指令。Leader把客户端发过来的指令做为一条新的日志条目加到日志中区,随后发起AppendEntries RPC请求将指令发送给其它节点。当日志条目被安全地复制(大多数节点已经将该日志条目写入日志当中)后,则Leader将这个日志条目应用到它的状态机中,而后把执行结果返回给客户端。

   那么Follower 是怎么接受来自Leader 的AppendEntries 的呢?先说一下一致性检查的过程。因为Follower可能落后Leader一些日志(好比以前挂了后来恢复了),或者比Leader多一些日志(好比这个结点是上一个term的Leader,有一些日志还没Commited就挂了),而raft要求Follower要完整复制Leader的日志,因须要进行一致性检查。在发送AppendEntries  RPC时,Leader会包含最新日志的前一个条目的索引和任期号。若是Follower在日志中找不到包含相同索引号和任期号的条目,那么它将会拒接接受新的日志条目。

  Leadre针对每一个Follower维护了一个nextIndex,表示下一个要发送给Follower的日志条目的索引。当一个Leader刚被选举出时,将nextIndex初始化为本身最新日志的index+1。若是AppendEntries 请求被拒绝,Leader会减少nextIndex进行重试,直到在某个位置Leader和Follower的日志一致,则AppendEntries  RPC成功,Follower上冲突的日志条目会所有删除并加上Leader的日志。这时,Follower的日志就会和Leader保持一致。

以前任期日志条目的处理

  本轮任期的Leader不能提交一个以前任期内的日志条目,不然可能会出现下述状况

 

 

 

  1. 在阶段a,term为2,S1是Leader,且S1写入日志(term, index)为(2, 2),而且日志被同步写入了S2;
  2. 在阶段b,S1离线,触发一次新的选主,此时S5被选为新的Leader,此时系统term为3,且写入了日志(term, index)为(3, 2);
  3. S5还没有将日志推送到Followers变离线了,进而触发了一次新的选主,而以前离线的S1通过从新上线后被选中变成Leader,此时系统term为4,此时S1会将本身的日志同步到Followers,按照上图就是将日志(2, 2)同步到了S3,而此时因为该日志已经被同步到了多数节点(S1, S2, S3),所以,此时日志(2,2)能够被commit了(即更新到状态机);
  4. 在阶段d,S1又很不幸地下线了,系统触发一次选主,而S5有可能被选为新的Leader(这是由于S5能够知足做为主的一切条件:1. term = 5 > 4,2. 最新的日志为(3,2),比大多数节点(如S2/S3/S4的日志都新),而后S5会将本身的日志更新到Followers,因而S二、S3中已经被提交的日志(2,2)被截断了,这是致命性的错误,由于一致性协议中不容许出现已经应用到状态机中的日志被截断。

为了不这种错误,Raft要求只有Leader当前term里的日志能够被提交。固然,因为日志匹配特性,以前的日志条目也会被提交。这样的话因为term被更新,就不会出现4里面说的S5会被选为leader的状况了。

 

参考连接:https://zhuanlan.zhihu.com/p/27207160

相关文章
相关标签/搜索