raft协议是一种共识协议,用来管理log复制。它的效果等同于multi-Paxos,并且与它的效率相当。但是与paxos的结构完全不同。raft协议更好理解,并且更加容易实现一个实际的分布式系统。将共识协议划分成几个模块:leader选举,日志复制和安全。raft也包括一个改变集群membership的机制,采用overlapping majorities来保证安全。
Introduction
所谓共识协议,就是允许分布式系统中的一些机器坏掉依然可以对外提供正确且一致的服务。raft协议与现有的很多共识协议很相像,但是它也依然有自己的特点:
- 强leader:比如,日志记录只能从leader到其它服务器。这个假设简化了日志复制的管理,使得raft协议更加容易理解。
- leader选举:raft用随机timer选举leader,来有效解决leader冲突问题,并且相对于其它的协议,仅仅引入很少量的机制。
- 成员改变:Raft用于更改群集群中服务器的机制使用了一种新的联合共识方法,其中两种不同配置的多数在转换期间重叠。 这允许群集在配置更改期间继续正常运行。
Replicated state machines
共识算法在复制状态机的环境下产生了。在这个方法中,集群中服务器的状态机根据相同状态的相同副本进行计算并且对外提供一致的服务,尽管一些服务器可能变得不可用。状态机用于解决分布式系统中的一系列容错问题。复制状态机采用日志复制的方式执行,如同图1所示。每个服务器存储了一份包含了一系列命令的日志。状态机按照日志中命令的顺序进行执行。每个机器上的日志以相同的顺序包含完全相同的指令,因此状态机执行的是相同的指令顺序。因为状态机是确定的,每个执行相同的操作,得到相同的输出。
因此保持日志复制的一致性是共识协议的主要工作。服务器上的共识模块从客户端接收命令,并且将其添加到它们的日志。它(这台服务器的共识模块)还要与其它服务器上的共识模块进行通信,确保每一份日志最终都以相同的顺序包含相同的指令,即便有一些机器fail。一旦指令被正确地复制了,每个服务器的状态机按照日志的指令顺序进行操作,然后将结果返回给客户端。这样做的结果呢就是集群中的所有服务器形成了单个高可靠的状态机。
能应用于实际系统的共识协议一半具有以下特点:
- 在所有的非拜占庭条件下,共识协议都保证安全,从来不返回不正确的结果。包括出现网络延迟,分区,丢包,复制和重排。
- 完全实用的,只要集群中大多数的机器可以进行操作,可以互相通信,并且可以与客户端通信。比如,一个拥有五台机器的集群可以容忍任意两台机器的failure。假设服务器因停止而失败; 他们可能稍后从稳定存储状态恢复并重新加入集群。
- 它们不依赖于时间来确保日志的一致性:错误的时钟和极端的消息延迟在最坏的情况下可能导致可用性问题。
- 在通常情况下,只要集群中的大多数服务器响应了单轮远程过程调用rpc,命令就可以完成; 少数慢速服务器不影响整体系统性能。
The raft consensus algorithm
raft首先选举产生一个leader,然后将管理日志复制的权利完全地交给leader。leader从客户端接收log entries,并将其复制到其它服务器上,并且告诉其它服务器什么时候能够可以安全地将这些log entries安全地应用于状态机。拥有一个leader可以简化复制日志的管理,比如,leader可以决定将新的entries放到log的什么位置,并且不用询问其它服务器。一个leader可能fail,也可能和其它的服务器失联,这个时候将会选出新的leader。
有了leader这个方法,raft将共识问题解藕成三个相对独立的子问题。在接下来的三个小结将分别介绍。
- leader选举:当一个已经存在的leader fails,新的leader必须被选出来。
- 日志复制:leader 必须接收来自客户端的日志条目,并且将其复制到集群中的服务器上,使得其它的日志条目与其相同。
- 安全:raft的主要安全特征是状态机安全特征,如果任何服务器将一个日志条目应用于其状态机,那么其它的服务器将不会应用一个相同index的不同的日志条目。后面将会描述raft是如何保证这个特征的,解决方案依赖于选举机制中的一个限制条件。
描述完共识协议之后,本节还将讨论可用性问题和timing 在系统中的角色。
Raft basics
一个raft集群包含若干个服务器:5是一个典型的数字,允许集群中的两台机器失效。每台服务器在任何时刻都只会处于三种状态:leader,follower,candidate。常规情况下,集群中只有一个leader,其他的机器都是followers。followers都是被动的:它们不发起任何的请求,仅仅对leader和candidates的请求作出响应。leader处理所有的客户端请求(如果一个客户端联系了一个follower,这个follower将其重定向到leader。第三种状态是candidate,用于选出一个新的leader。图4是机器状态和转换关系,接下来讨论转换问题。
raft将时间划分为任意长度的term,如图5所示,term的标号是连续的数字,每个term开始的时候进行选举,在这个阶段,一个或多个candidate试图成为一个leader。如果一个candidate成为leader,他将在这个term剩下的时间内执行leader的任务。在一些情况会发生投票破裂的问题,这样的话,这个term将会以无leader而结束,然后在一个新的term内重新进行选举,raft保证在一个term内至多有一个leader。
不同的服务器可以在不同的时间观察不同terms之间的转换,并且在某些情况下,服务器可能不会观察到选举甚至在整个term。 term在Raft中充当逻辑时钟,它们允许服务器检测过时的信息,例如过时的领导者。 每个服务器存储一个当前的term编号,该编号随着时间的推移单调增加。 当服务器通信时,交换当前term number; 如果一个服务器的term number当前小于另一个服务器的当前termnumber,则它将其当前term number更新为更大的值。 如果candidate或leader发现其term已过期,则会立即恢复为follower状态。 如果服务器收到带有过期的term number的请求,它将拒绝该请求。
raft服务器采用远程过程调用rpc来通信,基础的共识协议只要求两种类型的rpc:RequestVote rpc是在选举期间由candidates发起的,AppendEntries rpc是由leader发起的,用于复制日志条目,并且提供一种类型的心跳。第三种rpc发生在snapshot在服务器之间转移的时候,如果服务器未及时收到响应,则会重试RPC,并且它们并行发出RPC以获得最佳性能。
Leader election
raft用一种心跳机制来触发leader选举。当服务器启动的时候,它们首先成为followers。一个服务器只要能接收到从leader或者candidates发来的合法的rpc请求,它就将保持follower状态。为了保持自己的权威,leaders周期性地给followers发送心跳包(不带log entries的AppendEntries rpcs)。如果一个follower在一段时间内没有收到通信,称为选举超时,那么这个follower就假设目前没有可见的leader,并且开始新一轮的选举。
为了开始一轮选举,一个follower给它当前的term+1,并且将状态转为candidate状态,接着它给自己投一票,然后向集群中其它的服务器并行地发送RequestVote rpc。一个candidate保持当前的状态直到以下三件事之一发生:1)它赢得了选举;2)另一个服务器成为leader; 3)一个term以无leader结束。这三个状态将分别予以介绍。
一个candidate如果接收到集群中majority的投票,就能赢得选举。在给定的term内,每个服务器以先来先服务的策略,只能至多给一个服务器投票(后面会添加一个新的限制条件)。majority rule在给定term内至多一个服务器成为leader。一旦一个candidate赢得了选举,它将成为leader。它接着会将心跳消息发送给所有其它的服务器,并且建立起leader权威,阻止新的选举。
当等待投票的时候,一个candidate可能会收到一个声称自己是leader的服务器发来的AppendEntries rpcs。如果leader的term(包含在自己的rpc里)至少和candidate的term number一样大,那么candidate就会认为这个leader是合法的,并且退回到follower状态。如果rpc里的term比candidate当前的term小,那么candidate拒绝rpc,并且继续保持candidate状态。
第三中可能的输出是,一个candidate既没有赢得选举,也没有失去选举:如果很多followers同时变成了candidate,那么选举将会破裂,没有服务器获得多数票。当这个情况发生的时候,每个candidate会停止计时,并且开始新一轮的选举(增加自己的term