赞
踩
在分布式系统CAP理论解析中提到,分布式一致性算法为了使基于分布式系统架构下的所有节点进行事务处理过程中能够保持原子性和一致性而设计的一种算法。本文介绍几种常用的一致性算法,包括2PC、3PC、共识算法Paxos、基于日志的复制算法Raft、Zookeeper的ZAB协议等。
二阶段提交2PC是一致性协议算法,可以保证数据的强一致性,该算法能够解决很多临时性系统故障(包括进程、网络节点、通信等故障),被广泛地使用于关系型数据库系统中。
2PC协议中系统分为协调者和参与者,整个过程分为两个阶段:
1) 阶段1:Prepare请求阶段
2) 阶段2:Commit提交阶段
2PC协议的优点是原理简单、实现方便,但也有以下缺点:
为了解决2PC过程中同步阻塞和数据不一致的问题,3PC协议在协调者和参与者中都引入超时机制,并且把两阶段提交协议的第一个阶段拆分成了两步:询问,然后再锁资源,最后真正提交,包括CanCommit、PreCommit和doCommit三个阶段。
1)CanCommit阶段
3PC的CanCommit阶段和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
2)PreCommit阶段
协调者根据参与者的反应情况来决定是否可以继续事务的PreCommit操作。根据响应情况,有以下两种可能。
3)DoCommit阶段
该阶段进行真正的事务提交,也可以分为以下两种情况:
Paxos由莱斯利•兰伯特(Leslie Lamport)于1998年在《The Part-Time Parliament》论文中首次公开,最初的描述使用希腊的一个小岛Paxos,描述了Paxos小岛中通过决议的流程,并以此命名这个算法,但是这个描述理解起来比较有挑战性。后来在2001年,莱斯利•兰伯特重新发表了朴实的算法描述版本《Paxos Made Simple》
Paxos算法解决的问题是在一个可能发生消息可能会延迟、丢失、重复的分布式系统中如何就某个值达成一致,保证不论发生以上任何异常,都不会破坏决议的一致性。
Paxos算法中存在5种角色:client、acceptor、proposer、learner和leader,但在实际的实现中,一个服务可能同时扮演一个或者多个角色。
1)阶段1A:Prepare
在Prepare阶段,一个Proposer会创建一个Prepare消息,每个Prepare消息都有唯一的提案编号n。n并不是将要提案的内容,而只是一个唯一的编号,用来标志这个Prepare的消息。 n必须比该Proposer之前用过的所有编号都大,一般来说我们可以以数字递增的方式来实现这个编号。 接下来Proposer会把该编号发送给Acceptors,只有大多数Acceptors接收到Proposer发来的消息,该消息才算是发送成功。
2)阶段1B:Promise
当一个Acceptor收到从Proposer发过来的Prepare消息时候,会有两种情况:
3)阶段2A:Accept
如果一个Proposer收到半数以上Acceptor对其发出的编号为N的Prepare请求的响应,那么它就会发送一个针对[N,V]提案的Accept请求给半数以上的Acceptor。注意:V就是收到的响应中编号最大的提案的value(某个acceptor响应的它已经通过的{acceptN,acceptV}),如果响应中不包含任何提案,那么V就由Proposer自己决定
4)阶段2B:Accepted
如果Acceptor收到一个针对编号为N的提案的Accept请求,只要该Acceptor没有对编号大于N的Prepare请求做出过响应,它就接受该提案。如果N小于Acceptor以及响应的prepare请求,则拒绝,不回应或回复error(当proposer没有收到过半的回应,那么他会重新进入第一阶段,递增提案号,重新提出prepare请求)
在上面的运行过程中,每一个Proposer都有可能会产生多个提案。但只要每个Proposer都遵循如上述算法运行,就一定能保证算法执行的正确性。
客户端发起request请求到Proposer,然后Proposer发出提案并携带提案的编号1,分别发给每一个Acceptor;每一个Acceptor根据编号是否满足大于1,将投票结果通过Propose阶段反馈给Proposer;Proposer收到Acceptor的结果判断是否达到了多数派,达到了多数派则向Acceptor发出Accept请求,并携带提案的具体内容V;Acceptor收到提案内容后向Proposer反馈Accepted表示收到,并将提案内容交给Learner进行备份。
#1:Prepare(N=1)
#2:if(1>0) Promise(1,(Va,Vb,Vc))
#3:Accept(N=1,V=1)
#4:Accepted(N=1,V=1)
虽然Accetor3出现异常,没有向Proposer反馈,但是Proposer此时收到的接受提案的反馈有2个Acceptor,仍然满足多数派的情况,此时仍然能够将提案内容继续写入的,所以后续的Accept的发送只需要发送给剩下的两个Acceptor即可。
#1:Prepare(N=1)
#2:if(1>0) Promise(1,(Va,Vb,null))
#3:Accept(N=1,V=1)
#4:Accepted(N=1,V=1)
Proposer失败的话表示收到Acceptor的Propose请求之后无法继续发送Accept请求,这个时候集群会重新选出另一个新的能够工作的Proposer,再从prepare阶段开始处理,同时Prepare的提案版本号会增加一个,但是提案的内容还是之前的内容。
Basic Paxos首先流程上复杂,实现极其困难,其次效率低(达成一致性需要2轮RPC调用),引入了Multi-Paxos进行优化改进。Multi-Paxos是针对basic Paxos流程进行拆分为选举和复制的过程,第一次发起投票流程在所有的Acceptor中确定一个Leader,第二次发起投票流程直接由Leader确认。
Raft协议一共包含如下3类角色:
Raft算法由leader节点来处理一致性问题。leader节点接收来自客户端的请求日志数据,然后同步到集群中其它节点进行复制,当日志已经同步到超过半数以上节点的时候,leader节点再通知集群中其它节点哪些日志已经被复制成功,可以提交到raft状态机中执行。
节点的状态切换状态机如图所示,图中标记了状态切换的6种路径,下面做一个简单介绍
如果一个candidate在一次选举中赢得leader,那么这个节点将在这个任期中担任leader的角色。但并不是每个任期号都一定对应有一个leader的,比如上面的情况3中,可能在选举超时到来之前都没有产生一个新的leader,那么此时将递增任期号开始一次新的选举。
1)在进行选举过程中,有几个重要的概念
2)选举详细过程
如果follower在election timeout内没有收到来自leader的心跳,则会主动发起选举。步骤如下:
在这个过程中,根据来自其他节点的消息,可能出现三种结果:
选举leader以后,系统可以对外进行工作。客户端的请求发送到leader,leader来调度这些并发请求的顺序,并保证leader和follower状态的一致性。在Raft算法中,将这些请求以及执行顺序告知followers,leader和followers以相同的顺序来执行这些请求,保证状态一致。
共识算法一般是通过复制状态机来实现的,复制状态机简单来说就是:相同的初识状态 + 相同的输入=相同的结束状态。 如何保证所有节点按照相同的顺序执行相同的输入,replicated log可以实现,log具有持久化、有序的特点,是大多数分布式系统的基石。因此,在raft算法中,leader将客户端请求封装到一个个log entry,然后将这些log entries复制到所有follower节点,然后大家按相同顺序应用log entry中的command,来保证状态一致性。
当系统(leader)收到一个来自客户端的写请求,到返回给客户端,整个过程从leader的视角来看会经历以下步骤:
可以看到日志的提交过程有点类似两阶段提交(2PC),不过与2PC的区别在于,leader只需要大多数(majority)节点的回复即可,这样只要超过一半节点处于工作状态则系统就是可用的。每个节点的日志并不完全一致,raft算法为了保证高可用,并不是强一致性,而是最终一致性,leader会不断尝试给follower发log entries,直到所有节点的log entries都相同。
Zab协议的全称是Zookeeper Atomic Broadcast(Zookeeper原子广播),是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议 ,是Zookeeper保证数据一致性的核心算法。Zab借鉴了Paxos算法,但又不像Paxos那样,是一种通用的分布式一致性算法,它是特别为Zookeeper设计的支持崩溃恢复的原子广播协议。
在Zookeeper中主要依赖Zab协议来实现数据一致性,基于该协议,zk实现了一种主备模型的系统架构来保证集群中各个副本之间数据的一致性。这里的主备系统架构模型,就是指只有一台客户端(Leader)负责处理外部的写事务请求,然后Leader客户端将数据同步到其他Follower节点。具体如下图所示:
上图显示了Zookeeper如何处理集群中的数据。所有客户端写入数据都是写入到主进程(称为 Leader)中,然后由Leader复制到备份进程(称为 Follower)中,从而保证数据一致性。从设计上看,和Raft类似。
Zookeeper内部有三个角色
ZAB协议主要有四个阶段:
Leader选举即通过投票完成leader选举,最后每个成员都会知道leader的epoch和leader id。整个Leader选举的流程如下所示:
投票的信息主要是类似vote (zxid,id),其中id唯一标识一个peer、zxid为当前peer最新的版本号。图中有三条白色箭头,分别代表三个节点的时间,每一个节点在某一个时间会有三条线。
ZAB 协议的消息广播过程使用的是一个原子广播协议,类似一个 二阶段提交过程。对于客户端发送的写请求,全部由 Leader 接收,Leader 将请求封装成一个事务 Proposal,将其发送给所有 Follwer ,然后,根据所有 Follwer 的反馈,如果超过半数成功响应,则执行 commit 操作(先提交自己,再发送 commit 给所有 Follwer)
如果集群中的 Learner 节点收到客户端的事务请求,那么这些 Learner 会将请求转发给 Leader 服务器。然后再执行如下的具体过程:
本文主要介绍了5中一致性算法,包括2PC、3PC、Paxos、Raft和Zab,2PC在传统的数据库中广泛使用,实现起来简单但是因为事务阻塞和数据一致性问题,已经不适用于分布式架构下的大规模架构的性能要求了。Paxos作为解决分布式一致性问题的通用算法,在Google的很多大型分布式系统如Chubby和Spanner中广泛使用,但是在实际工程中实现起来复杂,所以出现了很多优化算法,比如Raft和Zab。Zab是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议,Raft则是一种更为通用的一致性算法,在ETCD、TiDB等数据库存储产品中广泛使用,相对Paxos来说实现上也更为简单些。
参考资料
转载请注明原文地址:https://blog.csdn.net/solihawk/article/details/125384028
文章会同步在公众号“牧羊人的方向”更新,感兴趣的可以关注公众号,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。