Overview
- Paxos算法介绍
问题和假设
- Paxos算法解决的问题是,在不考虑出现消息篡改(即拜占庭错误)的情况下,如何在一个可能发生异常(消息延迟、丢失,进程慢、被杀死、重启等)的分布式系统中如何就某个值达成一致,保证不论发生以上任何异常,都不会破坏决议的一致性。
- Lamport最初在引入该算法的时候,举了一个有意思的例子来描述问题场景:
在一个叫Paxos的小岛上,岛上采用议会的形式来通过法令,议会中的议员通过信使进行消息的传递。同时要注意议员和信使随时有可能会离开议会厅,并且信使可能会重复传递消息,也可能一去不复返。因此,议会协议要保证在这种情况下法令仍然能够正确的产生,并且不会出现冲突。
算法
算法的提出与证明
算法角色
- 首先,介绍算法中的几大角色:
- proposers:提出提案,提案信息包括提案编号和提议的value;
- acceptors:收到提案后可以接受提案,被多数Acceptor接受的提案会被批准(关于“多数”在后面会有进一步介绍)
- learners:只能“学习”被批准的提案,但learners可以身兼数职。
- 划分角色后,就可以更精确地定义问题:
- 决议(value)只有在被proposers提出后才能被批准;
- 在一次Paxos算法的执行实例中,只批准一个value;
- learners只能获得被批准的value
- 作者通过不断加强上述三个约束(主要是第二个),获得了Paxos算法。
- 为了满足只批准一个value的约束,要求经“多数派(majority)”接受的value称为正式的决议。两组majority至少有一个公共的acceptor,如果每个acceptor只能接受一个value,约束2就能保证。这就产生了一个显而易见的新约束:
P1: 一个acceptor必须接受第一次收到的提案。 - 但是P1不是完备的。如果恰好一半acceptor接受的提案具有valueA,另一半valueB,那么就无法形成majority,无法批准任何一个value。
- 约束并不要求只批准一个提案,暗示可能存在多个提案,只要提案的value是一样的。于是可以产生P2: (注意value和提案的不同)
P2: 一旦一个具有value v的提案被批准,那么之后批准的提案必须具有value v。
注:通过某种方法(这不包括在Paxos算法之内)可以为每个提案分配一个编号,在提案之间建立一个全局关系,所谓”之后”都是指所有编号更大的提案。 - 如果P1和P2都能保证,那么约束2就能保证。批准一个value意味着多个acceptor接受了该value。因此,可以对P2进行加强。
P2a: 一旦一个具有value v的提案被批准,那么之后任何acceptor再次接受的提案必须具有value v。(P2a实际上就是P2的加强版) - 由于通信是异步的,P2a和P1会发生冲突。如果一个value被批准后,一个proposer和一个acceptor从休眠中苏醒,前者提出一个具有新的value的提案。根据P1,后者应当接受,根据P2a,则不应当接受。这种场景下P2a和P1有矛盾。于是需要换个思路,转而对proposers的行为进行约束。
P2b: 一旦一个具有value v的提案被批准,那么以后任何proposer提出的提案都必须具有value v。
由于acceptor能接受的提案必须由proposer提出,所以P2b蕴涵了P2a,是一个更强的约束。 - 但是根据P2b难以提出实现手段,因此需要进一步加强P2b。假设一个编号为m的value v以及被chosen(批准),来看看在什么情况下对任何编号n(n > m)的提案都含有value v。因为m已经被批准,显然存在一个acceptors的多数派C,它们都接受了v。考虑到任何多数派和C都至少有一个公共成员,可以找到一个蕴含P2b的约束P2c:
P2c: 如果一个编号为n的提案具有value v,那么至少存在一个多数派,要么它们所有人都没有接受编号小于n的任何提案,要么它们已经接受了所有编号小于n的提案中编号最大的那个提案具有value v。
可以用数学归纳法证明P2c蕴含P2b(略)。
- 为了满足只批准一个value的约束,要求经“多数派(majority)”接受的value称为正式的决议。两组majority至少有一个公共的acceptor,如果每个acceptor只能接受一个value,约束2就能保证。这就产生了一个显而易见的新约束:
决议的提出与批准
- 通过一个决议分为两个阶段:
- prepare阶段:
- proposer选择一个提案编号n,并将prepare请求发给acceptors中的一个多数派;
- acceptor收到prepare请求后,如果提案的编号大于它已经回复的所有prepare消息,则acceptor将自己上次接受的提案回复给proposer,并承诺不再回复小于n的提案;
- chosen阶段:
- 当一个proposer收到了多数acceptors对prepare的回复后,就进入批准阶段。它要向回复prepare请求的acceptors发送accept请求,包括编号n和根据P2c决定的value(如果根据P2c没有已经接受的value,那么它可以自由决定value);
- 在不违背自己向其他proposer的承诺的前提下,acceptor可以收到accpet请求后接受这个请求。
- prepare阶段:
- 在这个过程中,任何时候中断都可以保证正确性。例如如果一个proposer发现已经有其他proposers提出了编号更高的提案,则有必要中断这个过程。因此为了优化,在上述prepare过程中,如果一个acceptor发现存在一个更高编号的提案,则需要通知proposer,提醒中断这次提案。
提案的获取
- 接下来看learners如何获取提案。
方案一
- learner获取一个提案的前提是,该提案已被半数以上的acceptor批准。因此,最简单的做法就是一旦acceptor批准了一个提案,就将该提案发送给所有的learner。
- 显然,该做法虽然可以让learners尽快地获取被选定的提案,但是却需要让每个acceptor与所有的learner逐个进行一次通信,因此通信次数至少为二者个数的乘积。
方案二
- 可以让所有的acceptor将它们对提案的批准情况,统一发送给一个特定的learner(称为“主”learner),在不考虑拜占庭问题的前提下,我们假定learner之间可以通过消息通信来互相感知提案的选定情况。基于此,主learner被通知一个已被选定的提案时,它会负责通知其他的learner。
- 该方案大大减少了通信量,但引入了新的不稳定因素:主learner随时可能出现故障。
FYI
满地都是六便士,她却抬头看见了月亮。