2.从Paxos到Zookeeper分布式一致性原理与实践---一致性协议

 

1.2PC 与 3PC
	在分布式系统中,每一个机器节点虽然能够明确的知道自己在进行事务操作过程中的结果是成功或者失败,但却无法直接获取到其他分布式节点
  的操作结果。因此,当一个事务操作需要跨多个分布式节点的时候,为了保持事务处理的ACID特性,就需要引入一个称为'协调者'的组件来统一
  调度所有的分布式节点的执行逻辑,这些被调度的分布式节点则被称为'参与者'。协调者负责调度参与者的行为,并最终决定这些参与者是否要把
  本地事务真正进行提交。基于这个思想,衍生出了二阶段提交和三阶段提交两种协议。

  1.2PC
  	2PC,是 Two-Phase Commit 的缩写,即二阶段提交,是计算机网络尤其是在数据库领域内,为了使基于分布式系统架构下的所有节点在进行
  事务处理过程中能够保持原子性和一致性而设计的一种算法。通常,二阶段提交协议也被认为是一种一致性协议,用来保证分布式系统数据的一致性。
  目前,绝大部分的关系型数据库都是采用二阶段提交协议来完成分布式事务处理的,利用该协议能够非常方便的完成所有分布式事务参与者的协调,
  统一决定事务的提交或回滚,从而能够有效的保证分布式数据的一致性,因此二阶段提交协议被广泛的应用在许多分布式系统中。

  	协议说明:
  		顾名思义,二阶段提交协议是将事务的提交过程分成了两个阶段进行处理,其流程如下。

  	阶段一:提交事务请求
  		1.事务询问
  			协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待参与者的响应。
  		2.执行事务
  			各参与者节点执行事务操作,并将undo 和 redo 信息记录事务日志中。
  		3.各参与者向协调者反馈事务询问的响应
  			各个参与者成功执行了事务操作,那么就反馈给协调者Yes响应,表示事务可以执行;如果参与者没有成功执行事务,那么就反馈给协调者No响应,
  		  表示事务不可以执行。
  		由于上面讲述的内容在形式上近似是协调者组织各个参与者对一次事务操作的选票表态过程,因此二阶段提交协议的阶段的阶段一也被称之为'投票阶段',
  	  即各个参与者投票是否要继续执行接下去的事务提交操作。

  	阶段二:执行事务提交
  		在阶段二中,协调者会根据各个参与者的反馈情况来决定最终是否可以进行事务提交操作,正常情况下,包含以下2种可能:
  		1.执行事务提交
  			假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务提交。
  			1.发送提交请求
  				协调者向所有参与者节点发送Commit请求
  			2.事务提交
  				参与者接收到Commit请求后,会正式执行事务提交操作,并在完成提交之后释放在整个事务执行期间占用的事务资源
  			3.反馈事务提交结果
  				参与者在完成事务提交之后,向协调者发送Ack消息
  			4.完成事务
  				协调者接收到所有参与者反馈的Ack消息后,完成事务

  		2.中断事务
  			假如任何一个参与者向协调者反馈了No响应,或者在等待超时之后,协调者尚无法接收到所有参与者的反馈响应,那么就会中断事务。
  			1.发送回滚请求
  				协调者向所有参与者节点发出Rollback请求
  			2.事务回滚	
  				参与者接收到Rollback请求后,会利用其在阶段一记录的Undo信息来执行事务回滚操作,并在完成回滚之后释放整个事务执行期间占用的资源
  			3.反馈事务回滚结果
  				参与者在完成事务回滚之后,向协调者发送Ack消息
  			4.中断事务
  				协调者接收到所有参与者反馈的Ack消息后,完成事务中断

  		二阶段提交将一个事务的处理过程分为了投票和执行两个阶段,其核心是对每个事务都采用先尝试提交的处理方式,因此也可以将二阶段提交提交看做是一个
  	  强一致性的算法。

  	    优缺点:
  	    	二阶段提交协议的优点:原理简单,实现方便
  	    	二阶段提交协议的缺点:同步阻塞,单点问题,脑裂,太过保守

  	    	同步阻塞:
  	    		二阶段提交协议存在的最明显的也是最大的一个问题是同步阻塞,这会极大的限制分布式系统的性能。在二阶段提交的过程中,所有参与该事务操作的
  	    	  逻辑都处于阻塞状态,也就说,各个参与者在等待其他参与者响应的过程中,将无法进行其他任何操作。
  	    	单点问题:
  	    		协调者的角色在整个二阶段提交协议中起到了非常重要的作用。一旦协调者出现了问题,那么整个二阶段提交流程将无法运转,更为严重的是,如果协调者
  	    	  是在阶段二中出现问题的话,那额其他参与者将会一直处于锁定事务资源的状态中,而无法继续完成事务操作。
  	    	数据不一致:
  	    		在二阶段提交协议的阶段二,即执行事务提交的时候,当协调者向所有的参与者发送Commit请求之后,发生了局部网络异常或者是协调者在尚未发送完Commit
  	    	  请求之前自身发生了崩溃,导致最终只有局部参与者收到了Commit请求。于是,这部分收到了Commit请求的参与者就会进行事务的提交,而其他没有收到Commit
  	    	  请求的参与者则无法进行事务提交,于是整个分布式系统便出现了数据不一致的现象。
  	    	太过保守:
  	    		如果在协调者指示参与者进行事务提交询问的过程中,参与者出现了故障而导致协调者始终无法获取到所有参与者的响应信息的话,这时协调者只能依靠自身的超时
  	    	  机制来判断是否需要中断事务,这样的策略显得比较保守。换句话说,二阶段提交协议并没有涉及较为完善的容错机制,任意一个节点的失败都会导致整个事务的失败。

  2.3PC
  	3PC,是Three-Phase Commit 的缩写,即三阶段提交,是2PC的改进版,其将二阶段提交协议的'提交事务请求'过程一分为二,形成了由CanCommit,PreCommit和doCommit 三个
  阶段组成的事务处理协议。
    阶段一:CanCommit
    	1.事务询问
    		协调者向所有参与者发送一个包含事务内容的canCommit请求,询问是否可以执行事务提交操作,并开始等待各参与者的响应
    	2.各参与者向协调者反馈事务询问的响应
    		参与者在接收到来自协调者的canCommit请求后,正常情况下,如果其自身认为可以顺利执行事务,那么就会反馈Yes响应,并进入预备状态,否则反馈No响应。

    阶段二:PreCommit
    	在阶段二汇中,协调者会根据各参与者的反馈情况来决定是否可以进行事务的PreCommit操作,正常情况下,包含两种可能。
    	1.执行事务预提交
    		假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务预提交。
    		1.发送预提交请求
    			协调者向所有参与者节点发出preCommit请求,并进入Prepared阶段
    		2.事务预提交
    			参与者接收到 preCommit 请求后,会执行事务操作,并将Undo和Redo信息记录到事务日志中
    		3.各参与者向协调者反馈事务执行的响应
    			如果参与者成功执行了事务操作,那么就会反馈给协调者Ack响应,同时等待最终的指令:提交(commit)或中止(abort)

    	2.中断事务
    		假如任何一个参与者向协调者反馈了No响应,或者在等待超时之后,协调者尚无法接收到所有参与者的反馈响应,那么就会中断事务。
    		1.发送中断请求
    			协调者向所有参与者节点发出abort请求
    		2.中断事务
    			无论是收到来自协调者的abort请求,或者是等待协调者请求过程中出现超时,参与者都会中断事务。

    阶段三:doCommit
    	该阶段将进行真正的事务提交,会存在以下2种可能的情况:
    	1.执行提交
    		1.发送提交请求
    			进入这一阶段,假设协调者处于正常工作状态,并且它接收到了来自所有参与者的Ack响应,那么它将从'预提交'状态转换到'提交'状态,并向所有的
    		  参与者发送 doCommit 请求。
    		2.事务提交
    			参与者接收到 doCommit 请求之后,会正式执行事务提交操作,并在完成提交之后释放整个事务执行期间占用的事务资源。
    		3.反馈事务提交结果
    			参与者在完成事务提交之后,向协调者发送Ack消息
    		4.完成事务
    			协调者接收到所有参与者反馈的Ack消息后,完成事务

    	2.中断事务
    		进入这一阶段,假设协调者处于正常工作状态,并且有任意一个参与者向协调者反馈了No响应,或者在等待超时之后,协调者尚无法接收到所有参与者的反馈
    	  响应,那么就会中断事务。
    	    1.发送中断请求
    	    	协调者向所有的参与者节点发送abort请求
    	    2.事务回滚
    	    	参与者接收到abort请求之后,会利用其在阶段二中记录的Undo信息来执行事务回滚操作,并在完成回滚之后释放在整个事务执行期间占用的资源
    	    3.反馈事务回滚结果
    	    	参与者在完成事务回滚之后,向协调者发送Ack消息
    	    4.中断事务
    	    	协调者接收到所有参与者反馈的Ack消息后,中断事务

    	    需要注意的是,一旦进入阶段三,可能会存在以下两种故障:
    	    1.协调者出现问题
    	    2.协调者和参与者之间的网络出现故障
    	    无论出现哪种情况,最终都会导致参与者无法及时接收来自协调者的 doCommit 或者是 abort 请求,针对这样的异常情况,参与者都会在等待超时之后,继续
    	  进行事务提交。

    	优缺点:
    		优点:相较于二阶段提交协议,三阶段提交协议最大的优点就是降低了参与者阻塞的范围,并且能够在出现单点故障之后继续达成一致。
    		缺点:三阶段提交协议在去除阻塞的同时也引入了新的问题,那就是在参与者接收到 preCommit 消息后,如果网络出现了分区,此时协调者所在的节点和参与者
    	    无法进行网络的正常通信,在这种情况下,该参与者依然会进行事务的提交,这比如导致事务不一致。


2.Paxos 算法
	Paxos 是一种基于消息传递且具有高度容错特性的一致性算法。Paxos算法需要解决的问题是如何在一个可能发生上述异常的分布式系统中,快速且正确的在集群内部对某个
  数据的值达成一致,并且保证不论发生以上任何异常,都不会破坏整个系统的一致性。

    拜占庭将军问题:
    	拜占庭帝国有许多军队,不同军队的将军之间必须制定一个统一的行动计划,从而做出进攻或撤退的决定,同时,各个将军在地理上都是被分隔开来的,只能依靠军队的
      通信员来进行通信。然后,在所有的通信员中可能会存在叛徒,这些叛徒可能修改信息,从而达到欺骗将军的目的。

      从理论上来说,在分布式计算领域,试图在异步系统和不可靠的通道上来达到一致性状态是不可能的,因此在对一致性的研究过程中,都往往假设信道是可靠的。而事实上
    大多数系统都是部署在同一个局域网中,因此消息被篡改的情况非常罕见;另一方面,由于硬件和网络原因造成的消息不完成问题,只需要一套简单的校验算法即可避免---
    因此,在实际工程实践中,可以假设不存在拜占庭将军问题,也即假设所有的消息都是完整的,没有被篡改。

    兼职议会:
    	在古希腊有一个叫做 Paxos 的小岛,岛上采用议会的形式来通过令法,议会中的议员通过信使进行消息的传递。值得注意的是,议员和信使都是兼职的,他们随时有
      可能离开会议厅,并且信使可能会重复的传递消息,也可能一去不复返。因此,议会协议要保证在这种情况下法令仍然能够正确的产生,并且不会出现冲突。


3.Paxos 算法详解
	Paxos 作为一种提高分布式系统容错性的一致性算法,核心是一个一致性算法,'synod' 算法。

	问题描述:
	  假设有一组可以提出提案的进程的集合,那么对于一个一致性算法来说需要保证以下几点:
	  1.在这些被提出的提案中,只有一个会被选定
	  2.如果没有提案被选定,那么就不会有被选定的提案
	  3.当一个提案被选定后,进程应该可以获取被选定的提案信息

	  对于一致性来说,安全性(Safety)需求如下:
	  1.只有被提出的提案才能被选定
	  2.只能有一个值被选定
	  3.如果某个进程认为某个提案被选定了,那么这个提案必须是真的被选定的那个

	  在对 Paxos 算法的讲解过程中,我们不去精确定义其活性(Liveness)需求,从整体来说,Paxos 算法的目标就是要保证最终有一个提案会被选定,当提案被选定后,
	进程最终也能获取被选定的提案。

	  一个分布式算法有2个最重要的属性:安全性(Safety)和活性(Liveness)。简单来说,Safety 是指那些需要保证永远都不会发生的事情,Liveness则是指那些最终
	会一致的事情。

	  在该一致性算法中,有三种角色参与,我们用 Proposer,Acceptor 和 Learner 来表示。在具体的实现中,一个进程可能充当不止一种角色,在这里我们并不关心
	如何映射到各种角色。假设不同参与者之间可以通过收发消息进行通信,那么:
	  1.每个参与者以任意的速度执行,可能会因为出错而停止,也可能会重启。同时,即使一个提案被选定后,所有的参与者也都有可能失败或者重启,因此除非那些失败
	  或重启的参与者可以记录某些信息,否则将无法确定最终的值。
	  2.消息在传输过程中可能出现不可预知的延迟,也可能会重复或丢失,但是消息不会被损坏,即消息内容不会篡改(拜占庭式问题)

	  拜占庭将军问题同样是 Lamport 提出的一个点对点通信的基本问题,其认为在存在消息丢失的不可靠信道上视图通过消息传递的方式达到一致性是不可能的。

	提案的选定:
		要选定一个唯一提案的最简单方式莫过于只允许一个 Acceptor 存在,这样的话,Proposer 只能发送提案给该 Acceptor,Acceptor 会选择它接收到的第一个
	  提案作为被选定的提案。这种解决方法尽管实现起来非常简单,但是却很难让人满意,因为一旦这个 Acceptor 出现问题,那么整个系统就无法工作了。
	    因此要寻找更好的方式,例如可以使用多个 Acceptor 来避免单点问题。
	    在存在多个 Acceptor 的情况下,如何进行提案的选取:Proposer 向一个Accpetor 集合发送提案,同样,集合中的每个 Acceptor 都可能会批准(Accept)
	  该提案,当有足够多的 Acceptor 批准这个提案的时候,我们就可以认为该提案被选定了。那么,什么是足够多呢?我们假设足够多的 Acceptor 是整个Acceptor 
	  集合的一个子集,并且让这个集合大的可以包含 Acceptor 集合中的大多数成员,因为任意两个包含大多数 Acceptor 的子集至少有一个公共成员。另外我们再规定,
	  每一个 Acceptor 最多只能批准一个提案,那么就能够保证只有一个提案被选定了。

	推导过程:
		在没有失败和消息丢失的情况下,如果我们希望及时在只有一个提案被提出的情况下,仍然可以选出一个提案,这就暗示着如下的需求:
		P1:一个 Acceptor 必须批准它收到的第一个提案。

		上面这个需求就引出另外一个问题:如果多个提案被不同的 Proposer 同时提出,这可能会导致虽然每个 Acceptor 都批准了它收到的第一个提案,但是没有一个
	  提案是由多数人都批准的。这种情况下,是无法选举一个提案的。另外,即使只有2个提案被提出,如果每个提案都差不多一半的 Acceptor 批准了,此时即使只有一个
	  Acceptor 出错,都可能导致无法确定该选定哪个提案。
	    因此,在P1的基础上,再加上一个提案被选定需要半数以上的 Acceptor 批准的需求暗示着一个 Acceptor 必须能够批准不止一个提案。在这里,我们用一个全局
	  的编号来唯一标识每一个被 Acceptor 批准的提案,当一个具有 Value 值的提案被半数以上的 Acceptor 批准后,我们就认为该 Value 被选定了,此时我们也认为
	  该提案被选定了。需要注意的是,此处讲到的提案已经和 Value 不是一个概念了,提案变成了一个由编号和 Value 组成的组合,因此我们以 [编号,Value] 来表示
	  一个提案。

	    根据上面提到的内容,我们虽然允许多个提案被选定,但同时必须要保证所有被选定的提案都具有相同的Value值---这是一个关于提案Value的约定,结合提案的编号,
	  该约定可以定义如下:
	  	P2:如果编号为 M0,Value为V0的提案(即[M0,V0])被选定了,那么所有比编号M0更高的,且被选定的提案,其值必须也是V0。

	  	因为提案的编号是全序的,条件P2就保证了只有一个 Value 值被选定这一关键安全性属性。同时,一个提案被选定,其首先必须被至少一个 Acceptor 批准,因此
	  我们可以通过满足下面条件来满足P2:
	    P2a:如果编号为M0,Value值为V0的提案(即 [M0,V0] 被选定了,那么所有比 M0 更高的,且被 Acceptor 批准的提案,其Value 值必须也是 V0)。
	    至此,我们仍然需要 P1 来保证提案会被选定,但是因为通信是异步的,一个提案可能会在某个 Acceptor 还未收到任何提案时就被选定了。
	  	
	  	强化:
	  	P2b:如果一个提案 [M0,V0] 被选定后,那么之后任何 Proposer 产生的编号更高的提案,其值 Value 值都是 V0。
	  	因为一个提案必须在被 Proposer 提出后才能被 Acceptor 批准,因此P2b包含了 P2a,进而包含 P2。于是,接下来的重点就是论证 P2b 成立即可:
	  	  假设某个提案 [M0,V0] 已经被选定了,证明任何编号 Mn>M0 的提案,其 Value 值都是 V0。

	数学归纳法证明:
		P2c:对于任意的Mn和 Vn,如果提案 [Mn,Vn] 被提出,那么肯定存在一个由半数以上的 Acceptor 组成的集合S,满足以下两个条件的任意一个。
		1.S 中不存在任何批准过编号小于Mn的提案的 Acceptor
		2.选取S中所有 Acceptor 批准的批号小于 Mn 的提案,其中编号最大的那个提案其 Value 值是 Vn。

	    从上面的内容可以看到,从P1到 P2c 的过程其实是对一系列条件的逐步增强,如果需要证明这些条件可以保证一致性,那么就需要进行反向推导:
	    P2c => P2b => P2a => P2, 然后通过 P2 和 P1 来保证一致性。

	Proposer 生成提案:
		在 P2c 的基础上如何进行提案的生成。对于一个 Proposer 来说,获取那些已经被通过的提案远比预测未来可能会被通过的提案来的简单。因此,Proposer 在
	  产生一个编号为 Mn的提案时,必须要知道当前某一个将要或已经被半数以上 Acceptor 批准的编号小于 Mn 但为最大编号的提案。并且,Proposer 会要求所有的
	  Acceptor 都不要再批准任何编号小于Mn的提案---这就引出了如下生成算法。
	  1.Proposer 选择一个新的提案编号Mn,然后向某个 Accepotor 集合的成员发送请求,要求该集合中的 Acceptor 做出如下回应:
	  	1.向 Proposer 承诺,保证不再批准任何编号小于 Mn 的提案
	  	2.如果 Acceptor 已经批准过任何提案,那么其就向 Proposer 反馈当前该 Acceptor 已经批准的编号小于 Mn但为最大的那个提案的值。

	  	我们将该请求称为编号Mn的提案的 Prepare 请求。

	  2.如果 Proposer 收到了来自半数以上的 Acceptor 的响应结果,那么它就可以产生编号为 Mn,Value值为 Vn的提案,这里的 Vn 是所有响应中编号最大的提案的
	  Value 值。当然还存在一种情况,就是半数以上的 Acceptor 都没有批准过任何提案,即响应中不包含任何的提案,那么此时Vn的值就可以由 Proposer 任意选择。

	    在确定提案后,Proposer 就会将该提案再次发送给某个 Acceptor 集合,并期望获得它们的批准,我们称此请求为 Accept 请求。需要注意的一点是,此时接收
	  Accept 请求的 Acceptor 集合不一定是之前响应 Prepare 请求的 Acceptor 集合---任意两个半数以上的Acceptor 集合,必定包含至少一个公共的 Acceptor。

	Acceptor 批准提案:
		根据上面的内容,一个 Acceptor 可能会收到来自 Proposer 的两种请求,分别是 Proposer 的两种请求,分别是 Prepare 请求和 Accept 请求,对着2类
	  请求做出相应的条件分别如下:
	  1.Prepare 请求 : Acceptor 可以在任何时候响应一个 Prepare 请求
	  2.Accept 请求 : 在不违背 Accept 现有承诺的情况下,可以响应任何 Accept 请求

	    因此,对 Acceptor 逻辑的约束条件,大体可以定义如下:
	    P1a: 一个 Acceptor 只要尚未响应过任何编号大于 Mn 的 Prepare 请求,那么它就可以接受这个编号为 Mn 的提案
	    从上面这个约束条件中,我们可以看出,P1a 包含了 P1。同时,值得一提的是,Paxos 算法允许 Acceptor 忽略任何请求而不用担心破坏其算法的安全性。

	算法优化:
		接下来我们对这个算法做个初步优化,尽可能的忽略 Prepare 请求:
		假设一个 Acceptor 收到一个编号为 Mn 的 Prepare 请求,但此时该 Acceptor 已经对编号大于 Mn 的 Prepare 请求做出了响应,因此它肯定不会再
	  批准任何新的编号为 Mn 的提案,那么很显然,Acceptor 就没有必要对这个 Prepare 请求做出响应,于是 Acceptor 可以选择忽略这样的 Prepare 请求。
	  同时,Acceptor 也可以忽略掉那些它已经批准过的提案的 Prepare 请求。
	    通过这个优化,每个 Acceptor 只需要记住它已经批准的提案的最大的编号以及它已经做出 Prepare 请求响应的提案的最大编号,以便在出现故障或节点重启
	  情况下,也能保证P2c的不变性。对于 Proposer 来说,只要它可以保证不会产生具有相同编号的提案,那么就可以丢弃任意提案以及它所有的运行时状态信息。

	算法陈述:
		结合 Proposer 和 Acceptor 对提案的处理逻辑,可以得到类似于两阶段提交的算法的执行过程。
		阶段一:
			1.Proposer 选择一个提案编号Mn,然后向 Acceptor 的超过半数的子集成员发送编号为 Mn 的 Prepare 请求
			2.如果一个 Acceptor 收到一个编号为 Mn 的 Prepare 请求,且编号 Mn 大于该 Acceptor 已经响应的所有 Prepare 请求的编号,那么它就会将自己
		    已经批准过的最大的编号的提案作为响应反馈给 Proposer ,同时该 Acceptor 会承诺不会再批准任何编号小于 Mn 的提案。

		阶段二:
			1.如果 Proposer 收到来自半数以上的 Acceptor 对于其发出的编号为 Mn 的 Prepare 请求的响应,那么它就会发送一个针对 [Mn,Vn] 提案的Accept
		    请求给 Acceptor.注意,Vn 的值就是收到的响应中编码最大的提案的值,如果响应中不包含任何提案,那么它就是任意值。
		    2.如果 Acceptor 收到这个针对 [Mn,Vn] 提案的 Accept 请求,只要该 Acceptor 尚未对编号大于Mn的 Prepare 请求做出响应,它就可以通过这个提案

		当然,在实际运行过程中,每个 Proposer 都有可能产生多个提案,但只要每个Proposer都遵循上述的算法运行,就一定能够保证算法执行的正确性。值得一提的是,
	  每个 Proposer 都可以在任意时刻丢弃一个提案,哪怕针对该提案的请求和响应在提案被丢弃后到达,但根据 Paxos 算法的一系列规则,依然可以保证其在提案选定上的
	  正确性。事实上,如果某个Proposer 已经在试图生成编号更大的提案,那么丢弃一些旧的提案未尝不是一个好的选择。因此,如果一个 Acceptor 因为已经收到更大编号的
	  Prepare 请求而忽略某个编号更小的 Prepare 或者 Accept 请求,那么它也应当通知其对应的 Proposer,以便该 Proposer 也能够将该提案进行丢弃---这和上面的
	  '算法优化'部分中提到的丢弃是一致的。

	提案的获取:
		如何让Learner 获取提案,大体可以有以下几种方案:

		方案一:
			Learner 获取一个已经被选定的提案的前提是,该提案已经被半数以上的 Acceptor 批准。因此,最简单的做法就是一旦 Acceptor 批准了一个提案,就将该提案
		  发送给所有的Learner.
		    很显然,这种做法虽然可以让Learner 尽快的获取被选定的提案,但是却需要让每个 Acceptor 与所有的Learner 逐个进行一次通信,通信的次数至少为二者个数的
		  乘积。

		方案二:
			我们可以让所有的 Acceptor 将它们对提案的批准情况,统一发送给一个 Learner(主"Learner"),在不考虑拜占庭将军问题的情况下,我们假定 Learner 之间
		  可以通过消息通信来互相感知提案的选定情况。基于这样的前提下,当主 Learner 被通知一个提案已经被选定时,它会负责通知其他 Learner。
		    在这种方案中,Acceptor 首先会将得到的批准的提案发送给主 Learner,再由其同步给其他 Learner,因此较方案一而言,方案二虽然需要多一个步骤才能将提案
		  通知到所有的Learner,但其通信次数却大大减少了,通常只是Acceptor和 Learner 的个数总和。但同时,该方案引入了一个新的不稳定因素:主Learner随时可能
		  出现故障。

		方案三:	
			方案二存在的最大问题是存在单点问题。因此,可以将主 Learner 的范围扩大,即 Acceptor 可以将批准的提案发送给一个特定的Learner集合,该集合中的每个
		  Learner 都可以在一个提案被选定后通知所有其他的 Learner。这个Learner集合中的Learner个数越多,可靠性就越好,但同时网络通信的复杂度也越高。

    通过选举主 Proposer 保证算法的活性:
    	为了保证 Paxos 算法流程的可持续性,以避免陷入'死循环',就必须选择一个主 Proposer,并规定只有猪 Proposer 才能提出议案。这样一来,只要主 Proposer
      和 过半的 Acceptor能够正常通信,那么但凡主 Proposer提出一个更大编号的提案,该提案终将被批准。当然,如果Proposer发现当前算法流程中已经有一个编号更大的
      提案被提出或者正在接收批准,那么它会丢弃当前这个编号小的提案,并最终能够选出一个编号足够大的提案。因此,如果系统中有足够多的组件(包括 Proposer,Acceptor,
      和其他网络通信组件)能够正常工作,那么通过选择一个主 Proposer,整套Paxos算法流程就能够保持活性。

小结:
	二阶段提交协议解决了分布式事务的原子性问题,保证了分布式事务的多个参与者要么都执行成功,要么执行失败。但是,在二阶段解决了部分分布式事务问题的同时,
  依然存在一些难以解决的问题,如同步阻塞,无限等待和'脑裂'等问题。
    三阶段提交协议则是二阶段提交协议的基础上,添加了PreCommit 过程,从而避免了二阶段提交协议中的无限等待问题。
    而Paxos算法引入了'过半'的理念,通俗的讲,就是少数服从多数的原则。同时,Paxos 算法支持分布式节点角色之间的轮换,这极大的避免了分布式单点的出现,因此,Paxos
  既解决了无限等待问题,也解决了'脑裂'问题。

https://www.zhihu.com/question/19787937

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值