Raft算法是什么
分布式系统在极大提高可用性、容错性的同时,带来了一致性问题。Raft算法能够解决分布式系统环境下的一致性问题。过去,Paxos一直是分布式协议的标准,但是Paxos难于理解,更难以实现。后来斯坦福大学提出来Raft算法。Raft是用于管理复制日志的一致性算法,它的效果相当于(multi-)Paxos。
原文请参考:https://github.com/maemual/raft-zh_cn/blob/master/raft-zh_cn.md
帮助大家理解算法的页面:https://raft.github.io/raftscope/index.html
Raft算法的的独特性
- 强领导者:和其他一致性算法相比,Raft使用一种更强的领导能力形式。比如,日志条目只从领导者发送给其他的服务器。简化了对复制日志的管理并且使得Raft算法更加易于理解。
- 领导选举:Raft算法使用一个随机计时器来选举领导者。这种方式只是在任何一致性算法都必须实现的心跳机制上增加了一点机制。在解决冲突的时候会更加简单快捷。
- 成员关系调整:Raft使用一种共同一致的方法来处理集群成员变换的问题,在这种方法下,处于调整过程中的两种不同的配置集群中大多数机器会有重叠,这就使得集群在成员变换的时候依然可以继续工作。
Raft一致性算法
Raft将一致性问题分解成三个先对独立的子问题
- 领导选举:一个新的领导人需要被选举出来,当现存的领导人宕机的时候
- 日志复制:领导人必须从客户端接收日志然后复制到集群中的其它节点,并且强制要求其他节点的日志保持和自己相同
- 安全性:如果有任何的服务器节点已经应用了一个确定的日志条目到它的状态机中,那么其他服务器节点不能在同一个日志索引位置应用一个不同的指令。
领导选举
在任何时刻,每个服务器都处于以下三个状态之一:
领导人(Leader):通常情况下,系统中只有一个领导人,并且其他节点全部都是跟随者。领导人处理所有客户端请求(如果一个客户端跟跟随者联系,跟随者会把请求重定向给领导人)
跟随者(Follower):不会发送任何请求,只是简单响应来自领导者或者候选人的请求
候选人(Candidate):选举领导人时使用
Raft把时间分割成任意长度的任期,如图。每一段任期从一次选举开始。Raft保证了在一个给定任期内,最多只有一个领导者。
选举流程
- 领导人周期性的向所有跟随者发送心跳包来维持自己的权威
- 如果一个跟随者在一段时间里没有收到任何消息,也就是选举超时,那么他就会认为系统中没有可用领导人并且发起选举以选出新的领导者
- 该跟随者增加自己的当前任期号并且转换到候选人状态,然后向集群中其他节点发送给自己投票的请求。
- 当一个候选人从整个集群的大多数服务器节点获得了针对同一个任期号的选票,就赢得了选举并成为领导人。每一个服务器最多会对一个任期号投出一张选票,按照先来先服务原则。
- 等待投票的时候,候选人可能会收到声明它是领导人的请求。如果这个领导人的任期号不小于候选人当前任期号,那么候选人会承认领导人合法并回到跟随者状态。小于当前任期号,那么候选人拒绝该请求。
- 候选人既没有赢得选举也没有输(多个候选人平分选票),每个候选人都会超时,然后通过增加当前任期号开始一轮新的选举。然后,没有其他机制的话。可能会无限次重新选举
Raft算法使用随机选举超时时间的方法来确保很少会发生选票瓜分的情况,就算发生也能很快的解决。
日志复制
- 客户端每一个请求都包含一条被复制状态机执行的指令
- 领导人把该指令作为一条新的日志条目附加到日志中,然后并行的发起附加条目给其他的服务器,让他们复制这条日志条目
- 当这条日志条目被安全的复制,领导人会应用这条日志条目到它的状态机中,然后把执行结构返回给客户端
- 如果跟随者崩溃或者运行缓慢,再或者网络丢包,领导人会不断重复尝试,直到所有跟随者都最终存储了所有日志条目
- 在领导人将创建的日志条目复制到大多数的服务器上的时候,日志条目就会被提交
- 领导人的日志中之前的所有日志条目也都会被提交,包括由其他领导人创建的条目
- 领导人跟踪了最大的将会被提交的日志项的索引,并且索引值会被包含在未来的所有附加日志请求(包括心跳包)。跟随者知道一条日志条目已经被提交,那么他也会将这个日志条目应用到本地的状态机中。
一致性保证
领导人崩溃的情况会使得日志处于不一致的状态,如图(方框中数字为任期):跟随者缺少一些日志(a、b),会有一些未被提交的日志条目(c、d)。更复杂的场景f,在任期2、任期3被选为领导人,但在日志被提交之前,这个服务器宕机了。
一致性实现
- 一致性检查:在发送附加日志请求的时候,领导人会把新的日志条目紧接着之前的条目的索引位置和任期号包含在里面,若跟随者在它的日志中找不到包含相同索引位置和任期号的条目,那么他就会拒绝接收新的日志条目。
- 领导人处理不一致是通过强制跟随者直接复制自己的日志来解决。这意味着跟随者中的冲突日志会被领导人的日志覆盖
不一致日志查找流程
- 领导人针对每一个跟随者维护了一个nextIndex,这表示下一个需要发送给跟随者的日志条目的索引地址
- 领导人初始化所有的nextIndex为自己的最后一条日志的index+1
- 一致性检查失败,跟随者拒绝之后,领导人就会减小nextIndex值并进行重试
- 最终nextIndex会在某个位置使得领导人和跟随者日志达成一致,当附加日志请求成功,这时就会把跟随者冲突的日志条目全部删除并且加上领导人日志。
安全性
到目前为止描述的机制并不能充分的保证每一个状态机会按照相同的顺序执行相同的指令。例如:一个跟随者可能会进入不可用状态同时领导人已经提交了若干的日志条目,然而这个跟随者可能会被选举为领导人并且覆盖这些日志条目,因此,不同状态机可能会执行不同的指令序列。
通过在领导选举的时候增加一些限制来完善Raft算法,这一限制保证了任何的领导人对于给定的任期号,都拥有了之前任期的所有被提交的日志条目。
选举限制
Raft使用投票的方式来阻止一个候选人来赢得选举,除非这个候选人包含了所有已经提交的日志条目。
投票请求中包含了候选人的日志信息,投票人会拒绝掉那些日志没有自己新的投票请求。
Raft 通过比较两份日志中最后一条日志条目的索引值和任期号定义谁的日志比较新。如果两份日志最后的条目的任期号不同,那么任期号大的日志更加新。如果两份日志最后的条目任期号相同,那么日志比较长的那个就更加新。
提交之前任期内的日志条目
- Raft永远不会通过计算副本数目的方式提交之前任期的日志条目。只有领导人当前任期里的日志条目通过计算副本数目可以被提交。一旦当前任期的日志条目被提交,之前的日志条目也都会被间接的提交。
- 当领导人复制之前任期里的日志时,Raft会为所有日志保留原始的任期号
-
这在提交规则上产生了额外的复杂性。在其他一致性算法中,如果一个新的领导人要重新复制之前任期里的日志时,必须使用当前任期号
-
Raft使用的方法更容易辨别出日志,它可以随着时间和日志的编号对日志维护同一个任期编号
-
Raft中的新领导人只需要发送更少的日志条目(其他算法必须在他们被提交之前发送更多的冗余日志条目来为他们重新编号)
优点
Raft算法具有强一致、高可靠、高可用等优点,体现在:
强一致性:虽然所有节点的数据并非实时一致,但Raft算法保证Leader节点的数据最全,同时所有请求都由Leader处理,所以在客户端角度看是强一致性的。
高可靠性:Raft算法保证了Committed的日志不会被修改,State Matchine只应用Committed的日志,所以当客户端收到请求成功即代表数据不再改变。Committed日志在大多数节点上冗余存储,少于一半的磁盘故障数据不会丢失。
高可用性:从Raft算法原理可以看出,选举和日志同步都只需要大多数的节点正常互联即可,所以少量节点故障或网络异常不会影响系统的可用性。即使Leader故障,在选举超时到期后,集群自发选举新Leader,无需人工干预,不可用时间极小。但Leader故障时存在重复数据问题,需要业务去重或幂等性保证。
高性能:与必须将数据写到所有节点才能返回客户端成功的算法相比,Raft算法只需要大多数节点成功即可,少量节点处理缓慢不会延缓整体系统运行。
参考文章(字体挺花哨,内容也挺全):https://blog.youkuaiyun.com/daaikuaichuan/article/details/98627822