春秋五霸,是指东周春秋时期相继称霸主的五个诸侯,“霸”,意为霸主,便是诸侯之领袖。
典型的好比齐桓公,晋文公,春秋时期诸侯国的称霸,与今天要讨论的Raft算法很像。git
Raft 适用于一个管理日志一致性的协议,相比于 Paxos 协议 Raft 更易于理解和去实现它。
为了提升理解性,Raft 将一致性算法分为了几个部分,包括领导选取(leader selection)、日志复制(log replication)、安全(safety),而且使用了更强的一致性来减小了必须须要考虑的状态。github
分布式存储系统一般经过维护多个副原本提升系统的availability,带来的代价就是分布式存储系统的核心问题之一:维护多个副本的一致性。算法
Raft协议基于复制状态机(replicated state machine),即一组server从相同的初始状态起,按相同的顺序执行相同的命令,最终会达到一直的状态,一组server记录相同的操做日志,并以相同的顺序应用到状态机。数据库
Raft有一个明确的场景,就是管理复制日志的一致性。安全
如图,每台机器保存一份日志,日志来自于客户端的请求,包含一系列的命令,状态机会按顺序执行这些命令。
一致性算法管理来自客户端状态命令的复制日志,保证状态机处理的日志中的命令的顺序都是一致的,所以会获得相同的执行结果。服务器
先看一段动画演示,Understandable Distributed Consensus 。网络
相比Paxos,Raft算法理解起来直观的很。并发
Raft算法将Server划分为3种状态,或者也能够称做角色:分布式
负责Client交互和log复制,同一时刻系统中最多存在1个。区块链
被动响应请求RPC,从不主动发起请求RPC。
一种临时的角色,只存在于leader的选举阶段,某个节点想要变成leader,那么就发起投票请求,同时本身变成candidate。若是选举成功,则变为candidate,不然退回为follower
状态或者说角色的流转以下:
在Raft中,问题分解为:领导选取、日志复制、安全和成员变化。
复制状态机经过复制日志来实现:
Raft中使用心跳机制来出发leader选举。当服务器启动的时候,服务器成为follower。只要follower从leader或者candidate收到有效的RPCs就会保持follower状态。若是follower在一段时间内(该段时间被称为election timeout)没有收到消息,则它会假设当前没有可用的leader,而后开启选举新leader的流程。
Term的概念类比中国历史上的朝代更替,Raft 算法将时间划分红为任意不一样长度的任期(term)。
任期用连续的数字进行表示。每个任期的开始都是一次选举(election),一个或多个候选人会试图成为领导人。若是一个候选人赢得了选举,它就会在该任期的剩余时间担任领导人。在某些状况下,选票会被瓜分,有可能没有选出领导人,那么,将会开始另外一个任期,而且马上开始下一次选举。Raft 算法保证在给定的一个任期最多只有一个领导人。
Raft 算法中服务器节点之间通讯使用远程过程调用(RPCs),而且基本的一致性算法只须要两种类型的 RPCs,为了在服务器之间传输快照增长了第三种 RPC。
RPC有三种:
(1)follower增长当前的term,转变为candidate。
(2)candidate投票给本身,并发送RequestVote RPC给集群中的其余服务器。
(3)收到RequestVote的服务器,在同一term中只会按照先到先得投票给至多一个candidate。且只会投票给log至少和自身同样新的candidate。
candidate节点保持(2)的状态,直到下面三种状况中的一种发生。
Raft中使用随机选举超时时间来解决当票数相同没法肯定leader的问题。
日志复制(Log Replication)主要做用是用于保证节点的一致性,这阶段所作的操做也是为了保证一致性与高可用性。
当Leader选举出来后便开始负责客户端的请求,全部事务(更新操做)请求都必须先通过Leader处理,日志复制(Log Replication)就是为了保证执行相同的操做序列所作的工做。
在Raft中当接收到客户端的日志(事务请求)后先把该日志追加到本地的Log中,而后经过heartbeat把该Entry同步给其余Follower,Follower接收到日志后记录日志而后向Leader发送ACK,当Leader收到大多数(n/2+1)Follower的ACK信息后将该日志设置为已提交并追加到本地磁盘中,通知客户端并在下个heartbeat中Leader将通知全部的Follower将该日志存储在本身的本地磁盘中。
Raft算法的论文相比Paxos直观不少,更容易在工程上实现。
能够看到Raft算法的实现已经很是多了,https://raft.github.io/#implementations
这里用ETCD来关注Raft的应用,ETCD目标是构建一个高可用的分布式键值(key-value)数据库,基于 Go 语言实现。
Etcd 主要用途是共享配置和服务发现,实现一致性使用了Raft算法。
更多Etcd的应用能够查看文档:https://coreos.com/etcd/docs/latest/
Zookeeper 使用了一种修改后的 Paxos 协议。
在 Zookeeper 中,始终分为两种场景:
在这个场景里,系统中缺少 Leader(primary),经过一个相似 paxos 协议的过程完成 Leader 选举。
在 Leader activation 场景中完成 leader 选举及数据同步后,系统转入 Active messaging 场景,在 active messaging 中 leader 异常后,系统转入 Leader activation 场景。
不管在那种场景,Zookeeper 依赖于一个全局版本号:zxid。zxid 由(epoch, count)两部分组成, 高位的 epoch 部分是选举编号,每次提议进行新的 leader 选举时 epoch 都会增长,低位的 count 部分 是 leader 为每一个更新操做决定的序号。能够认为,一个 leader 对应一个惟一的 epoch,每一个 leader 任期内产生的更新操做对应一个惟一的有序的 count,从而从全局的视野,一个 zxid 表明了一个更新操做的全局序号(版本号)。
Zookeeper 经过 zxid 将两个场景阶段较好的结合起来,且能保证全局的强一致性。因为同一时刻只有一个 zookeeper 节点能得到超过半数的 follower,因此同一时刻最多只存在惟一的 leader;每一个 leader 利用 FIFO 以 zxid 顺序更新各个 follower,只有成功完成前一个更新操做的才会进行下一个更新操做,在同一个 leader 任期内,数据在全局知足 quorum 约束的强一致,即读超过半数的节点 必定能够读到最新已提交的数据;每一个成功的更新操做都至少被超过半数的节点确认,使得新选举 的 leader 必定能够包括最新的已成功提交的数据。
分布式协议一个著名问题就是 split brain 问题。
简单说,就是好比当你的 cluster 里面有两个结点,它们都知道在这个 cluster 里须要选举出一个 master。那么当它们两之间的通讯彻底没有问题的时候,就会达成共识,选出其中一个做为 master。可是若是它们之间的通讯出了问题,那么两个结点都会以为如今没有 master,因此每一个都把本身选举成 master。因而 cluster 里面就会有两个 master。
区块链的分叉其实相似分布式系统的split brain。
通常来讲,Zookeeper会默认设置:
Majority 就是一种 Qunroms 的方式来支持Leader选举,能够防止 split brain出现。奇数个节点能够在相同容错能力的状况下节省资源。
两阶段提交系统具备彻底的C,很糟糕的A,很糟糕的P。
首先,两阶段提交协议保证了副本间是彻底一致的,这也是协议的设计目的。再者,协议在一个节点出现异常时,就没法更新数据,其服务可用性较低。最后,一旦协调者与参与者之间网络分化,没法提供服务。
Paxos 协议和Raft算法都是强一致性协议。Paxos只有两种状况下服务不可用:一是超过半数的 Proposer 异常,二是出现活锁。前者能够经过增长 Proposer 的个数来 下降因为 Proposer 异常影响服务的几率,后者自己发生的几率就极低。最后,只要能与超过半数的 Proposer 通讯就能够完成协议流程,协议自己具备较好的容忍网络分区的能力。