一致性的要求:
- 当只有一个提案被提出时,必须批准这个提案。
- 只可能存在一个被批准的提案。
- 如果某个进程认为一个提案被批准了,那么这个提案必须是已经批准的
为了满足第一点,当只有一个提案被提出时,Acceptor必须得接受这个提案才能批准这个提案。所以得出P1。
P1:Acceptor必须接受它第一个收到的提案。
如果Acceptor接受了一个提案,那么它就不能再接受比这个提案更早的提案。所以这里引入了一个number的概念,每次产生提案时,number自动增长。
第二点,只能存在一个被批准的提案,所以当一个提案被批准之后,后面的提案也只有这个值才能被批准。
P2:如果一个【M0,V0】的提案被批准了,那么比M0更大的提案只有value为V0时才会被批准。
由于一个提案只有被至少一个Acceptor接受才能被批准,所以:
P2a:如果一个【M0,V0】的提案被批准了,那么比M0更大的提案只有value为V0时才会被Accptor接受。
但是当【M0,V0】被批准时,可能存在一些Accptor还没有接受到任何的提案,根据P1条件,一个M0更大的提案且value不为V0也会被这些Acceptor接受,这显然与P2a矛盾了。所以做出如下改进:
P2b:如果一个【M0,V0】的提案被批准了,那么比M0更大的提案只有value为V0时才可以被提出。
由于只有提案被提出了,才能被Acceptor接受,所以P2b包含了P2a,进而包含了P2。所以只需要证明P2b成立即可。
P2c:对于任意的Mn和Vn,如果【Mn,Vn】的提案被提出,那么肯定存在一个由半数以上的Acceptor组成的集合S,满足以下条件的一个。
- S中不存在任何接受过编号小于Mn的提案的Acceptor。
- 选取S中所有Acceptor接受的编号小于Mn的提案,其中编号最大的那个提案其value肯定为Vn。
只要一直保证P2c的正确性,就可以满足P2b了。
想要保证P2c的正确性,一个编号为n的提案想要被提出,那么必须学习比n小且编号最大的提案。这引出了提案生成算法。
1). Proposer选择一个新的提案编号n,并发送给一部分Acceptor,要求这些Acceptor做出如下回应:
- 保证不接受任何提案编号小于n的提案。
- 返回其接受过的编号小于n且编号最大的提案的值,如果存在的话。
我们称之为编号为n的提案的prepare请求。
2). 如果Proposer收到了来自半数以上额Acceptor的响应结果,那么它就可以产生编号为n、值为v的提案,这里的v是所有响应中编号最大的提案的value值。如果响应中不存在任何提案值,那么v就可以由该Proposer任意选择。
Proposer把这个提出的提案发送给一部分Acceptor(和之前的集合不一定相同),并期望他们接受这个请求。我们称之为accept请求。
这些都是Proposer的算法,下面是Acceptor的算法:
P1a:一个Acceptor只要没有响应过编号比n大的提案的prepare请求时,就可以接受一个编号为n的提案。