Raft协议简析

2017-08-27  本文已影响0人  little田同学

什么是Replicated state machines(复制状态机):

一致性算法之所以可以保证在有节点挂掉时也能够继续服务, 就是因为有Replicated state machines的存在。 在分布式系统中, 有两种方式来实现这个复制状态机

  1. 用一个专门节点负责记录整个集群的元信息, 如HDFS, GFS
  2. 每个节点都会记录replicated log,确保每个节点的log最终都包含了相同的请求, 并且是同样的顺序

一致性算法一般有一下特点:

  1. 保证安全(不会返回错误数据)
  2. 只有半数以上的节点存活就可以继续提供服务
  3. 不依赖时钟来提供一致性, 最多会造成不可用
  4. 通常只要半数以上节点完成请求就算成功, 小部分慢节点不会影响整个系统的性能

为啥不用Paxos?

  1. 不清晰, 难以理解
  2. 不好实现, 只提供了single-decree Paxos的细节, 没有给出multi-Paxos的细节

Raft一致性算法

Raft算法首先会选举一个leader, 然后又leader来管理replicated log。 leader会从client处接收请求, 然后转发给别的节点, 并且告诉这些节点什么时候可以把这些请求应用在状态机上(落地)。 当一个leader挂了的时候, 会马上选举出一个新的leader。 由上可知, Raft将一致性问题拆分成了3个独立的子问题:

  1. Leader选举
  2. 日志的复制(Log replication)
  3. Safty: 不能有错误数据
Figure3 Logs Organization

Logs 组织的形式如图所示。 当leader收到一个Log entry时, 每个log entry都会存储一个带有term number的state machine命令。 Term number是用来探测log之间的不一致性并且保证Figure3的一些特性。 每个log也还带有他们在log里的索引数字。

当leader认为这个entry是可以成功应用到状态机上, 那么这个entry就被成为commited。Raft保证所有commited entry最终都会被应用到所有的节点上。

当一个entry被成功复制到半数以上的节点后, 这个log就可以认为成功写入了。并且会将leader之前的写入也视为commit。

设计Raft日志机制不仅简化了系统的行为, 也保证了正确性。 保证了Figure3的以下特性
1. 当不同log中的两个entry有相同的term和index, 那么这两个entry就是相同的
2. 当不同log中的两个entry有相同的term和index, 那么这两个entry之前的所有entry也都是相同的

Paste_Image.png

当leader发现follower的log跟自己的不同时, 他会针对每个follower维护一个nextIndex。 这个nextIndex就是Leader下次会发第几个entry给这个follower。 而follower也会拒绝这个append entry的rpc。

Safety

Figure 3
  1. 仅有第一点的保证我们仍旧可能会遇到问题。 如上图所示, a) s1成为leader,部分拷贝了index 2; b) s1挂了, s5成为leader, 写入index 3; c)s5又挂了, s1再次成为leader并且继续将index 2拷贝到其余follower; d) s1又一次挂了, s5成为leader(获得2,3,4的选票), 将自己所有的s3拷贝到别的机器并且覆盖掉了index 2; e)如果c阶段没有挂那么日志会被拷贝到s2,s3, 之后s5就不会被选为leader。
    上图演示了写入数据可能会被覆盖的问题, 那么如何避免这个问题。 Raft规定绝不通过计算副本数的方式commit 之前term的log entries。 只有当前term的log enties使用计算副本的方式来提交。 对于之前的term来说,当一个log通过这个方式提交成功了,那么他之前的所有log都算commit成功了。

    如何证明这个结论的正确性, 论文用反证法进行了论证:

Figure 4

如Figure 4所示, 如果term T commit的数据在之后的term U丢失了, 那么
1. 这个log一定不在Leader-U的log中(因为leader不会覆盖旧数据)
2. Leader-T把这个日志复制给了大多数节点并且Leader-U收到了大多数节点的投票, 所以至少有一个节点是既收到了这个entry并且又给Leader-U投票了
3. 那么这个投票的节点也一定收到了所有Leader-T的commited entries
4. 因为这个投票节点把票投给了U, 那么说明Leader-U也至少有所有这个节点的entries
由此可知, 如果投票节点和Leader-U 共享了之前的log, 那么Leader-U肯定会有所有投票节点的entry。 另外, Leader-U的last-log-term必须比T大, 而投票节点的term至少是T。之前term的leader在复制entry给Leader-U时也必须包含了之前的这个entry。 投票节点和之前term的leader都会有这个entry, 所以Leader-U也不会没有这个entry。可下结论所有大于T的term的leader绝对包含了所有term T commited的entries。

上一篇下一篇

猜你喜欢

热点阅读