最终一致性Basic-Paxos算法
Posted 点融黑帮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最终一致性Basic-Paxos算法相关的知识,希望对你有一定的参考价值。
Paxos算法概述
Paxos算法又被称为两阶段算法,请注意不是实现分布式事务的两阶段提交协议。Paxos算法的工作场景是基于CAP原理构建的分布式系统,是在这样的环境中如何高效率的达到数据的最终一致性;而两阶段/三阶段提交协议的工作场景是基于AICD原则的数据强一致性系统。
Paxos算法中有四个角色Client(议题产生者)、Proposer(正式提议者)、Acceptor(投票决策者)和Learner(最终结果学习者),这四个角色中Client和Learner角色是两个广义的概念,而真正完成算法的是Proposer角色和Acceptor角色,所以很多技术文章中都是重点讲解后两个角色的工作过程。Proposer角色是真正的提议发起者,负责发起提议投票、总结提议投票结果以及变更后发起新的投票;Acceptor角色是决策者,对于某个提案发表自己的投票结果,并交由Proposer角色进行处理,各个Acceptor角色都有自己的投票结果,不受其它Acceptor角色的影响。
总的来说Paxos算法在处理这样一个场景:当分布式系统中的多个Proposer对于某件事的结果不能达成一致时,就发起一个提案,由多个Acceptor负责进行投票并让多个Proposer对于这件事的结果达成最终一致。“这件事”可以是各种事情,例如“选主”,再例如K所代表的变量被同时赋予V1和V2两个值甚至更多的值,等等。这就是最终一致性的一种表现:每个Proposer对某件事情的判断过程可能在某段时间内可能是不一致的,但最终在客户端Client上呈现的结果将是一致的。
需要说明的是,Paxos算法最早由莱斯利·兰伯特(Leslie Lamport)提出,在他的论文中《The Part-Time Parliament》本来就介绍了Paxos算法的多种变体,加上在实际应用中各技术人员又加入了自己的理解,所以才出现了Paxos算法许多不一样的实现版本,但实际上这些算法版本中各角色的工作都有其处理原则,只要掌握了这些处理原则,理解Paxos就不难了。
Basic-Paxos算法理论
虽然说Paxos算法和两阶段提交协议的设计思路完全不一样,但前者借鉴了后者的一些思想——即分为准备阶段(Prapare)和赋值阶段(Accept) 。为了顺利的完成数据最终一致性这个工作目标,在整个工作过程中Proposer角色和Acceptor角色要分别保持以下的的工作原则:
l Proposer和Acceptor一个负责发起提议,一个负责响应提议。后者要尽量回复前者的每一个请求,无论这次请求根据Acceptor的处理原则是成功了还是失败了。如果Proposer在规定的时间内没有获得Acceptor的响应,则往最坏的情况来进行考虑。
l 针对一个提议X的多轮投票,各个Proposer需要保证自己发起的后一轮投票轮次编号(vote)一定大于前一轮投票轮次编号。而各个Proposer不必保证自己的投票轮次是全局最大的,当然为了减少在第一阶段的授权冲突,也可以保证新的投票轮次全局最大(这个原因分析在后文中会详细讨论)。
l 什么情况下针对一个议题X,Proposer不再发起新一轮投票并认为得到了最终一致的数据呢?当Proposer收集了各个Acceptor的最终投票值,并发现其中至少N/2 + 1个Acceptor的最终值都是V,则认为议题X的最终结果为V。实际上这个工作规则属于Proposer角色,但很多时候Proposer、Proposer、Acceptor都是一个应用程序。
l 在Prapare阶段,Acceptor需要保证不接受投票轮次编号(vote)小于等于当前PrepareVote的投票轮次的授权(发起)申请。
l 在Accept阶段,Acceptor需要保证不接受投票轮次编号(vote)小于当前PrepareVote的投票轮次的赋值申请。以上两条工作原则是最重要,为什么Pasox算法会有若干种变体呢?其原因就是在算法应用实现阶段,具体的算法实现在保证这两个基本工作原则下,为了提高工作效率而对实现过程进行微调。
Basic-Paxos算法过程
一、Prapare准备阶段
首先需要介绍几个在Acceptor角色上需要被持久化保存的数据属性:
l PrepareVote保存了当前Acceptor接收到的已完成投票授权的最大投票轮次
l AcceptedVote保存了当前Acceptor在赋值阶段完成投票赋值的投票轮次
l AcceptedValue保存了当前Acceptor在赋值阶段被赋予的值
1.第一个阶段Proposer和Acceptor至少要完成一次网络通讯,其主要目的是确定针对提议X的当前投票轮次是否能被授权。换句话说,根据Acceptor在准备阶段的工作原则,即使确定当前投票轮次的编号值是大于Acceptor中记录的PrepareVote的值。处理过程很简单,即Proposer向所有Acceptor发出关于发起提议X的新一轮投票的申请,并等待各个Acceptor进行响应。当然会有一个超时时间,如果超过这个时间还没有得到Acceptor的响应,则认为已经被拒绝。如果有超过N/2 + 1个节点在规定的时间内没有回复响应,那就说明整个选举系统发现了问题,则终止操作抛出错误,向客户端反馈异常信息。
2.收到这个发起新的一轮投票操作的授权请求后,各个Acceptor开始判断是否可以进行授权。判断的原则只与PrepareVote有关,既是如果当前申请的投票轮次小于等于PrepareVote的赋值,则拒绝授权;其它情况都要接受授权,并更改PrepareVote属性为当前新的投票伦次编号。这里有一个隐藏含义,即这个Acceptor新授权的投票轮次编号,一定大于之前PrepareVote的值。
3.Proposer将负责汇总所有Acceptor的响应情况,并根据汇总的情况判断下一步的操作。无论Acceptor是授权这次投票还是拒绝这次投票,给出的响应信息中都最好包括当前Acceptor所记录的PrepareVote、AcceptedVote和AcceptedValue信息,这样有利于Proposer分析为什么会被Acceptor拒绝。下图展示了Proposer在汇总所有Acceptor的响应时可能出现的各种情况:
当然还有一种情况三,就是超过(包括)N/2 + 1个Acceptor节点在规定的时间内没有反馈结果,这种情况直接判定Paxos系统崩溃,所以就不做进一步讨论了。请注意,无论是上图的哪种情况,只要至少N/2 + 1个Acceptor节点的AcceptedValue为同一个值,就认为提议X的结果达到了最终一致,整个Paxos算法过程也结束。
1.1 在Proposer得到的响应情况一中,至少N/2 + 1个Acceptor允许这轮投票。这些Acceptor就形成了一个集合Q,这个集合Q将继续下一步骤的操作。这时集合Q中的Acceptor是否已有AcceptedValue就很重要了:如果集合Q中没有任何一个Acceptor的AcceptedValue属性有值,则当前Proposer会在下一步提议自己的值为集合Q中每一个Acceptor的赋值目标;如果集合Q中至少存在一个Acceptor的AcceptedValue属性有值,则Proposer会选择一个AcceptedVote最大的AcceptedValue属性值,作为当前Proposer会在下一步进行Acceptor赋值的目标。
1.2 在Proposer得到的响应情况二中,始终未达到N/2 + 1个Acceptor允许这轮投票——无论是不满足Acceptor的授权原则还是Acceptor超时未响应。只要至少N/2 +1个Acceptor所回复的AcceptedValue属性值相同,则表示针对提议X已经形成了最终一致的结果,无需再进行投票了。否则,Proposer会将自己的投票轮次编号进行增加后,再发起投票——这个增加规则后续再讨论,读者目前可以认为是+1。
二、Accept赋值阶段
一旦有N/2 + 1个Acceptor节点授权了本轮投票,Proposer就可以进入第二阶段——赋值阶段,第二阶段将以上一阶段形成的多数派集合Q作为操作目标。如下图所示:
1.Proposer将会以上一阶段3.1步骤中所确定的value和自己的vote一起发送给集合Q中的每一个Acceptor,并等待回复。
2.Acceptor收到赋值请求后,将会按照判断原则确认是否进行赋值。这个判断原则是:如果当前收到的vote小于当前Acceptor的PrepareVote属性值,则不会进行赋值。为什么Acceptor上的PrepareVote会发生变化呢?这是因为在这个Proposer从第一阶段到第二阶段的操作间隙,另一个或者多个Proposer使用编号更大的vote发起了更新一轮的投票,并得到当前Acceptor的授权。如果当前收到的vote等于当前Acceptor的PrepareVote属性值则接受这次赋值,这时Acceptor将更改其AcceptedVote属性为vote,更改其AcceptedValue属性为value。
注意一种情况,Acceptor会不会在第二阶段操作时收到一个vote大于当前PrepareVote的赋值请求呢?这是不会的,因为任何Acceptor要更换PrepareVote,只可能更换比当前PrepareVote更大的值,所以之前被Acceptor同意授权的vote一定会小于或者等于当前Acceptor的PrepareVote属性值。
3.赋值操作完成后,Acceptor将向Proposer返回赋值操作后的AcceptedValue属性和AcceptedVote属性。换句话说就是,即使Acceptor拒绝了第二阶段的赋值操作,也要向Proposer返回AcceptedValue属性值。以下为Proposer端汇总统计时,可能出现的情况:
1.1 Acceptor收到集合Q中所有Acceptor的赋值结果后,就会进行汇总判断。如果发现所有赋值结果都是一样的value,则认为针对议题X形成了最终一致的结果。整个投票过程结束,value就是达成的最终值。
1.2 如果收到集合Q中所有Acceptor的赋值结果,并进行比较的过程中,发现任何一个赋值结果不一致,则认为赋值操作失败。这时Proposer会将自己的投票轮次编号进行增加后,再回到第一阶段重新发起投票。
以上是关于最终一致性Basic-Paxos算法的主要内容,如果未能解决你的问题,请参考以下文章
分布式系统架构系列讲解七(分布式一致性 7):Quorum NWR算法