PAXOS是为了解决分布式系统中的一致性问题。在描述中有三种角色:提案者(p)、批准者(a)、学习者(l)。提案者们提出了几种提案,通过该算法批准者选出一个提案被通过并被学习者学习。PAXOS的基本思想是只有提案者中的一个多数派批准一个提案,该值才被认为通过。下面是规则不断改变以满足要求的过程以及证明。
P1:一个批准者必须接受它收到的第一个提案。
这种规则其实就是p只能批准一个value。显然这个不能保证有个值能被一个多数派选出来,比如有提案者p1、p2,批准者a1、a2、a3(不幸挂掉了),此时a1批准了p1的提案,a2批准了p2的提案,此时是没有形成任何多数派的。
P1a:批准者在没有收到编号比N大的请求时才可能去批准N。
如果提案者只是单纯地只是提交V给批准者,这样很难做到有且仅有一个V会得到通过。所以在V上面加上一个属性:编号。这样每个提案的格式就变成了<N,V>。每个批准者在后面的过程中只需要满足这条简单的规则去运作就可以了。而做到这点也是很容易的,在本地记录接受到的请求的最大值,在接收到请求时与该值比较决定是否批准。
P2:如果V被一个多数派批准了,那么编号比V大的提案能被多数派批准的条件是其值是V。
提案者不断的提出新的提案<N,V>,当然提案到达批准者的顺序很可能不是按照编号从小到大的(这点好像比有且只有一个提案被通过更难保证)。如果<5,V0>被一个多数派批准了,那么根据P1a N<5 的提案不可能再被批准了。这时候如果能保证N>5的提案如果值不是V0就不会被一个多数派批准,那么便可以保证系统中产生一个提案。
这里允许提案者不断地提出<N,V>这种格式的提案,批准者也不断去批准提案。这样做的目的就是为了解决P1不能产生多数派的情况。但是这里的问题就是如何满足P2?显然是比较复杂的,如果能精确到每个批准者的行为就会简单一些。
P2a:如果V被一个多数派批准,那么编号比这个提案大的提案被任何批准者批准的条件是其值是V。
如果N>5的提案不会被任何一个批准者批准,那么当然是不会被一个多数派批准。
P2b:如果V被一个多数派批准,那么编号比V大的提案的值都应该是V。
如果一个提案根本没有被提出,当然不存在它被一个多数派批准的情况,这个规则把一定的工作量从批准者转移到提案者。也就是说,在提案者发现<N,V>已经被一个多数派批准,那么新产生的提案只能有两种<N<5,V0>和<N>5,V>。
P2c:提案者提出一个编号为N的V的前提是:存在一个多数派他们中没有人批准过编号小于N的任何提案,或者他们批准的编号小于N的最大的提案值为V。
假如<5,V0>被a1、a2批准,那么以后<6,V1>的天不可能被提出了。但是如果<6,V0>被提出来了,这是时候刚才批准过<5,V0>的批准者任何可以批准<6,V0>。
这样做的巧妙之处是如果<5,V0>系统中的一个多数派批准了,那么不需要每个提案者知道现在什么值已经被选举出来了就可以保证不会产生两个不同的提案。
有了上面的规则就大概明白了PAXOS算法的运行过程了。下面给出一个例子:有提案者p1、p2,批准者a1、a2、a3。刚开始任何批准者没有批准过任何提案,所有他们的状态如下:
N | V | |
a1 | 0 | 0 |
a2 | 0 | 0 |
a3 | 0 | 0 |
N | V | |
a1 | 1 | a |
a2 | 1 | 0 |
a3 | 0 | 0 |
N | V | |
a1 | 2 | a |
a2 | 2 | b |
a3 | 2 | b |
上面的这个例子中可以看出,不管在发送消息的过程中发生了什么状况都不会有两个提案被在一次选举中通过。而且看样子确实是不管网络出现什么问题都不会影响算法的正确运行。
似乎这篇文章应该结束了,但是还有几个地方需要想想。p1、p2之间是互相不知道的,那他们怎么保证不提交重复编号的提案?这个问题有一个简单的解决方法:p1提交的编号为奇数,p2提交的编号为偶数。当然在fast paxos中不存在这个问题,但是如果已经有一个leader了,那为什么不让leader去决定提案?
似乎我们侧地忘记了学习者这个角色。在刚才的过程中,在<1,a>发送给a2的时候挂掉了,但是a2在一段时候后又批准了该提案,将自己的决定告诉学习者。这时候学习者就接收到a1、a2关于提案<1、a>的决定,它被一个多数派通过了,但是真正被通过的是<2,b>,似乎功亏一篑。但是如果学习者是按照编号从小到大的顺序来处理提案就能解决这个问题。
----------------------------------------
个人理解,欢迎拍砖。