本篇文章讲的是分布式一致性算法的理解,主要是理解和整合2PC,3PC和paxos算法的:
首先我们说说分布式一致性的两个概念,一个是分布式设置不同的业务逻辑,来达到分布式的一致性,比如分布式系统收账服务系统和付账服务系统,收账表和付账表是不同的数据库,人是要付出了钱,机器收了钱,保证钱数是对的,才能保证分布式的一致性,这个应该叫分布式业务逻辑一致性,还有一种就是都是一样的数据库,只是主库和备份的关系,这个叫分布式数据一致性,掺杂业务逻辑。
先说2PC和3PC
为了解决分布式一致性问题,产生了不少经典的分布式一致性算法,本文将介绍其中的2PC和3PC。2PC即Two-Phase Commit,译为二阶段提交协议。3PC即Three-Phase Commit,译为三阶段提交协议。
分布式系统和分布式一致性问题
分布式系统,即运行在多台不同的网络计算机上的软硬件系统,并且仅通过消息传递来进行通信和协调。
分布式一致性问题,即相互独立的节点之间如何就一项决议达成一致的问题。
2PC
2PC,二阶段提交协议,即将事务的提交过程分为两个阶段来进行处理:准备阶段和提交阶段。事务的发起者称协调者,事务的执行者称参与者。
阶段1:准备阶段
1、协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待所有参与者答复。
2、各参与者执行事务操作,将Undo和Redo信息记入事务日志中(但不提交事务)。
3、如参与者执行成功,给协调者反馈YES,即可以提交;如执行失败,给协调者反馈NO,即不可提交。
阶段2:提交阶段
此阶段分两种情况:所有参与者均反馈YES、或任何一个参与者反馈NO。
所有参与者均反馈YES时,即提交事务。
任何一个参与者反馈NO时,即中断事务。
提交事务:(所有参与者均反馈YES)
1、协调者向所有参与者发出正式提交事务的请求(即Commit请求)。
2、参与者执行Commit请求,并释放整个事务期间占用的资源。
3、各参与者向协调者反馈Ack完成的消息。
4、协调者收到所有参与者反馈的Ack消息后,即完成事务提交。
附如下示意图:
中断事务:(任何一个参与者反馈NO)
1、协调者向所有参与者发出回滚请求(即Rollback请求)。
2、参与者使用阶段1中的Undo信息执行回滚操作,并释放整个事务期间占用的资源。
3、各参与者向协调者反馈Ack完成的消息。
4、协调者收到所有参与者反馈的Ack消息后,即完成事务中断。
附如下示意图:
2PC的缺陷
1、同步阻塞:最大的问题即同步阻塞,即:所有参与事务的逻辑均处于阻塞状态。
2、单点:协调者存在单点问题,如果协调者出现故障,参与者将一直处于锁定状态。
3、脑裂:在阶段2中,如果只有部分参与者接收并执行了Commit请求,会导致节点数据不一致。
由于2PC存在如上同步阻塞、单点、脑裂问题,因此又出现了2PC的改进方案,即3PC。
3PC
3PC,三阶段提交协议,是2PC的改进版本,即将事务的提交过程分为CanCommit、PreCommit、do Commit三个阶段来进行处理。
阶段1:CanCommit
1、协调者向所有参与者发出包含事务内容的CanCommit请求,询问是否可以提交事务,并等待所有参与者答复。
2、参与者收到CanCommit请求后,如果认为可以执行事务操作,则反馈YES并进入预备状态,否则反馈NO。
阶段2:PreCommit
此阶段分两种情况:
1、所有参与者均反馈YES,即执行事务预提交。
2、任何一个参与者反馈NO,或者等待超时后协调者尚无法收到所有参与者的反馈,即中断事务。
事务预提交:(所有参与者均反馈YES时)
1、协调者向所有参与者发出PreCommit请求,进入准备阶段。
2、参与者收到PreCommit请求后,执行事务操作,将Undo和Redo信息记入事务日志中(但不提交事务)。
3、各参与者向协调者反馈Ack响应或No响应,并等待最终指令。
中断事务:(任何一个参与者反馈NO,或者等待超时后协调者尚无法收到所有参与者的反馈时)
1、协调者向所有参与者发出abort请求。
2、无论收到协调者发出的abort请求,或者在等待协调者请求过程中出现超时,参与者均会中断事务。
阶段3:do Commit
此阶段也存在两种情况:
1、所有参与者均反馈Ack响应,即执行真正的事务提交。
2、任何一个参与者反馈NO,或者等待超时后协调者尚无法收到所有参与者的反馈,即中断事务。
提交事务:(所有参与者均反馈Ack响应时)
1、如果协调者处于工作状态,则向所有参与者发出do Commit请求。
2、参与者收到do Commit请求后,会正式执行事务提交,并释放整个事务期间占用的资源。
3、各参与者向协调者反馈Ack完成的消息。
4、协调者收到所有参与者反馈的Ack消息后,即完成事务提交。
中断事务:(任何一个参与者反馈NO,或者等待超时后协调者尚无法收到所有参与者的反馈时)
1、如果协调者处于工作状态,向所有参与者发出abort请求。
2、参与者使用阶段1中的Undo信息执行回滚操作,并释放整个事务期间占用的资源。
3、各参与者向协调者反馈Ack完成的消息。
4、协调者收到所有参与者反馈的Ack消息后,即完成事务中断。
注意:进入阶段三后,无论协调者出现问题,或者协调者与参与者网络出现问题,都会导致参与者无法接收到协调者发出的do Commit请求或abort请求。此时,参与者都会在等待超时之后,继续执行事务提交。
附示意图如下:
3PC的优点和缺陷
优点:降低了阻塞范围,在等待超时后协调者或参与者会中断事务。避免了协调者单点问题,阶段3中协调者出现问题时,参与者会继续提交事务。
缺陷:脑裂问题依然存在,即在参与者收到PreCommit请求后等待最终指令,如果此时协调者无法与参与者正常通信,会导致参与者继续提交事务,造成数据不一致。
以上总结:
2PC和3PC都还挺好理解,但是无论2PC或3PC,均无法彻底解决分布式一致性问题。
Google Chubby的作者Mike Burrows说过这个世界上只有一种一致性算法,那就是Paxos,其它的算法都是残次品!
介绍一下paxos的背景
Paxos算法是分布式技术大师Lamport提出的,主要目的是通过这个算法,让参与分布式处理的每个参与者逐步达成一致意见。 用好理解的方式来说,就是在一个选举过程中, 让不同的选民最终做出一致的决定。
Lamport为了讲述这个算法,假想了一个叫做Paxos的希腊成邦进行选举的情景,这个算法也是因此而得名。在他的假想中,这个城邦要采用民主提议和投票的方式选出一个最终的决议,但由于城邦的居民没有人愿意把全部时间和精力放在这种事情上,所以他们只能不定时的来参加提议,不定时来了解提议、投票进展,不定时的表达自己的投票意见。Paxos 算法的目标就是让他们按照少数服从多数的方式,最终达成一致意见。
首先我们要先思考Paxos到底解决了什么问题?
先看看答案吧,简单来说,paxos算法解决的就是一个最终一致性问题。假设一个集群有三个节点,Paxos可以让三个节点更快的达成一致。因为在Paxos中规定,如果某个节点写操作执行之前其他两个节点(也就是大多数的节点)的值已经相等并记为V,那么除非这次写入的值也为V,否则操作不能进行。而当其他两个节点的意见不统一时,采用高编号的节点的值。因此,最终一定会达到三个节点意见统一的状态。
接下来就是文章正文,paxos的算法。接受者相当于决策者,提议者会给决策者发送信息!
Paxos算法的具体情况:
1、在整个提议和投票过程中,主要的角色就是"提议者” (向”接受者”提出提议)和”接受者”(收到"提议者”的提议后,向”提议者”表达自己的意见)。
2、整个算法的大致过程为:
第一阶段:因为存在多个”提议者”,如果都提意见,那么“接受者”接受谁的不接受谁的?太混乱了。所以,要先明确哪个"提议者”是意见领袖有权提出提议,未来,”接受者” 们就主要处理这个”提议者”的提议了(这样,也可以在提出提议时就尽量让意见统一, 谋求尽早形成多数派)。
第二阶段:由上阶段选出的意见领袖提出提议,"接受者” 反馈意见。如果多数”接受者”接受了一个提议,那么提议就通过了。
3、必须要了解的其他相关背景:
1)怎么明确意见领袖呢?通过编号。每个"提议者”在第一阶段先报个号,谁的号大,谁就是意见领袖。如果不好理解,可以想象为贿选(文字下面为了方便表述,号越大的越有说话权,理解为贿赂的钱多)。每个提议者先拿着钞票贿赂一圈”接受者”,谁给的钱多,第二阶段”接受者”就听谁的。(注: 这里和下文提到的”意见领袖”,并环是一个新的角色,而是代表在那一轮贿赂成功的"提议者”。所以,请把意见领袖理解为贿赂中胜出的"提议者”即可)
2)有个跟选举常识不一样的地方,就是每个”提议者”不会执着于让自己的提议通过,而是每个”提议者”会执着于让提议尽快达成一致意见。 所以,为了这个目标,如果“提议者”在贿选的时候,发现”接受者”已经接受过前面意见领袖的提议了,即便”提议者”贿选成功,也会默默的把自己的提议改为前面意见领袖的提议。所以一旦贿赂成功,胜出的”提议者”再提出提议,提议内容也是前面意见领袖的提议(这样,在谋求尽早形成多数派的路上,又前进了一步)。
3)钱的多少很重要,如果钱少了,无论在第一,还是第二阶段“接受者”都不会尿你,直接拒绝。
4)上面2)中讲到,如果"提议者”在贿选时,发现前面已经有意见领袖的提议,那就将自己的提议默默改成前面意见领袖的提议。这里有一种情况,如果你是“提议者”, 在贿赂的时候,”接受者1”跟你说”他见过的意见领袖的提议是案1”,而”接受者2”跟你说“他见过的意见领袖提议是方案2”,你该怎么办?这时的原则也很简单,还是:钱的多少很重要!你判断一下是”接受者1”见过的意见领袖有钱,还是”接受者2”见过的意见领袖有钱?如何判断呢?因为”接受者”在被“提议者”贿赂的时候,自己会记下贿赂的金额。所以当你贿赂”接受者”时,- -一旦你给的贿赂多而胜出,”接受者” 会告诉你两件事情: a.前任意见领袖的提议内容(如果有的话),b.前任意见领袖当时贿赂了多少钱。这样,再面对刚才的情景时,你只需要判断一下"接受者1”和"接受者2”告诉你的信息中,哪个意见领袖当时给的钱多,那你就默默的把自己的提议,改成那个意见领袖的提议。
5)最后这一部分最有意思,但描述起来有点绕,如果不能一下子就理解可以先看后面的例子。在整个选举过程中,每个人谁先来谁后到,”接受者” 什么时间能够接到"提议者”的信息,完全不可控的。所以很可能一个意见领袖已经产生了 ,但是由于这个意见领袖的第一阶段刚刚开始, 绝大部分"接受者”还没有收到这个意见领袖的提议。结果,这时突然冲进来了一个新的土豪"提议者”,那么这个土豪"提议者”也是有机会让自己的提议胜出的!这时就形成了一种博弈: a. 上一个意见领袖要赶在土豪”提议者”贿赂到”接受者”前,赶到”接受者”面前上他接受自己的提议,否则会因为自己的之前贿赂的钱比土豪少而被拒绝。b.土豪"提议者”要赶在上一个意见领袖将提议传达给“接受者”前,贿赂到”接受者”,否则土豪”提议者”即便贿赂成功,也要默默的将自己的提议改为前任意见领袖的提议。这整个博弈的过程,最终就看这两个”提议者”谁的进展快了。但最终一定会有一个意见领袖,先得到多数"接受者”的认可,那他的提议就胜出了。
4、总结
好啦,故事到这里基本讲述完了,咱们来总结一下,其实Paxos算法就下面这么几个原则:
1) Paxos算法包括两个阶段:第一个阶段主要是贿选,还没有提出提议;第二个阶段主要根据第一阶段的结果,明确接受谁的提议,并明确提议的内容是什么(这个提议可能是贿选胜出“提议者”自己的提议,也可能是前任意见领袖的提议,具体是哪个提议,见下面第3点原则)。
2)编号(贿赂金额)很重要,无论在哪个阶段,编号(贿赂金额)小的,都会被鄙视(被拒绝)。3)在第一阶段中,一旦"接受者”已经接受了之前意见领袖的提议,那后面再来找这个”接受者”的”提议者”,即便在贿赂中胜出,也要被洗脑,默默将自己的提议改为前任意见领袖的提议,然后他会在第二阶段提出该提议(也就是之前意见领袖的提议,以力争让大家的意见趋同)。如果"接受者”之前没有接受过任何提议,那贿选胜出的"提议者”就可以提出自己的提议了。
5、举例
最后举个例子,加深一下印象:
有两个”提议者”和三个”接受者” 。
1)首先"提议者1”贿赂了3个"接受者”
2) 3个"接受者”记录下贿赂金额,因为目前只有一个"提议者”出价,因此$1就是最高的了,所以"接受者”们返回贿赂成功。此外,因为没有任何先前的意见领袖提出的提议,因此"接受者”们告诉"提议者1”没有之前接受过的提议(自然也就没有上一个意见领袖的贿赂金额了)。
3) “提以者1"向“接受者1”提出了自己的提以: 1号提以,并告知自己之前已賄賂$1。
4)“接受者1” 检查了一下,目前记录的贿赂金额就是$1,于是接受了这一提议, 并把1号提议记录在案。
5)在”提议者1”向"接受者2” "接受者3”发起提议前,土豪“提议者2”出现,他开始用$2贿赂”接受者1”与”接受者2”。
6) “接受者1”与"接受者2”立刻被收买,将贿赂金额改为$2。但是,不同的是: ”接受者1"告诉“提议者2”,之前我已经接受过1号提议了,同时1号提议的”提议者”贿赂过$1;而,"接受者2”告诉”提议者2”,之前没有接受过其他意见领袖的提议,也没有上一个意见领袖的贿赂金额。
7)这时, “提议者1”回过神来了,他向"接受者2”和”接受者3”发起1号提议,并带着信息”我前期已经贿赂过$1”。
8) ”接受者2” "接受者3”开始答复: ”接受者2”检查了一下自己记录的贿赂金额,然后表示,已经有人出价到$2了,而你之前只出到$1,不接受你的提议,再见。但”接受者3”检查了一下自己记录的贿赂金额,目前记录的贿赂金额就是$1,于是接受了这一提议,并把1号提议记录在案。
9)到这里, ”提议者1”已经得到两个接受者的赞同,已经得到了多数"接受者”的赞同。于是”提议者1”确定1号提议最终通过。
10) 下面,回到"提议者2”。刚才说到, ”提议者2”贿赂了”接受者1”和"接受者2”,被“接受者1”告知: "之前已经接受过1号提议了,同时1号提议的'提议者’贿赂过$1”,并被”接受者2”告知: "之 前没有接到过其他意见领袖的提议,也没有其他意见领袖的贿赂金额”。这时"提议者2”,拿到信息后,判断一下,目前贿赂过最高金额(即$1)的提议就是1号提议了,所以“提议者2”默默的把自己的提议改为与1号提议一致,然后开始向”接受者1””接受者2” 发起提议(提议内容仍然是1号提议),并带着信息:之前自己已贿赂过$2。
11) 这时”接受者1” ”接受者2”收到”提议者2”的提议后,照例先比对一下贿赂金额,比对发现”提议者2”之前已贿赂$2,并且自己记录的贿赂金额也是$2,所以接受他的提议,也就是都接受1号提议。
这里再多说一句:
回到上面的第5)步,如果”提议者2”第一次先去贿赂"接受者2”"接受者3” 会发生什么?那很可能1号提议就不会成为最终选出的提议。因为当”提议者2”先贿赂到了”接受者2””接受者3”,那等“提议者1” 带着议题再去找这两位的时候,就会因为之前贿赂的钱少($1<$2)而被拒绝。所以,这也就是刚才讲到可能存在博弈的地方: a.”提议者1”要赶在“提议者2”贿赂到"接受者2””接受者3” 之前,让”接受者2””接受者3” 接受自己的意见,否则”提议者1”会因为钱少而被拒绝; b.”提议者2”要赶在“提议者1”之前贿赂到”接受者”,否则”提议者2”即便贿赂成功,也要默默的将自己的提议改为“提议者1” 的提议。但你往后推演会发现,无论如何,总会有一个“提议者”的提议获得多数票而胜出。
以上,只是把大致的Paxos算法的思路介绍了一下,因为情景实在太复杂,比如: “提议
者”、 “接受者”如果是4个、5..... 比如: "提议者”与”接受者”之间的交互谁先谁后,等等各类情况。但是,其实都是能够严谨的推导出最后能够选出一个多数派的,不过篇幅就会太长了。大家有兴趣可以按照上面的思路,自己再模拟模拟"提议者”“接受者” 数量或多或少,交互或先或后的各种情况,结果肯定是最终唯一一个 提议会获得多数票而胜出。
回想当时自己看Paxos算法时,过很多的弯路,花了很长时间,这篇文章也是结合自己看Paxos算法时的一些心得所写,希望对初学者能有些启发。
参考网址:
https://www.zhihu.com/question/19787937
https://blog.csdn.net/zifanyou/article/details/84789022
https://www.cnblogs.com/esingchan/p/3917718.html
https://www.cnblogs.com/hugb/p/8955505.html