Paxos算法为什么说是Raft,Zab协议的鼻祖,及原理解析( 二 )


消息在传递过程中可能出现任意时长的延迟,可能会重复,也可能丢失 。但是消息不会被损坏,即消息内容不会被篡改(拜占庭将军问题) 。
推导过程最简单的方案——只有一个Acceptor
假设只有一个Acceptor(可以有多个Proposer),只要Acceptor接受它收到的第一个提案,则该提案被选定,该提案里的value就是被选定的value 。这样就保证只有一个value会被选定 。
但是,如果这个唯一的Acceptor宕机了,那么整个系统就无法工作了!
因此,必须要有多个Acceptor!

Paxos算法为什么说是Raft,Zab协议的鼻祖,及原理解析

文章插图
 
多个Acceptor
多个Acceptor的情况如下图 。那么,如何保证在多个Proposer和多个Acceptor的情况下选定一个value呢?
Paxos算法为什么说是Raft,Zab协议的鼻祖,及原理解析

文章插图
 
下面开始寻找解决方案 。
如果我们希望即使只有一个Proposer提出了一个value,该value也最终被选定 。
那么,就得到下面的约束:
P1:一个Acceptor必须接受它收到的第一个提案 。
但是,这又会引出另一个问题:如果每个Proposer分别提出不同的value,发给不同的Acceptor 。根据P1,Acceptor分别接受自己收到的value,就导致不同的value被选定 。出现了不一致 。如下图:
Paxos算法为什么说是Raft,Zab协议的鼻祖,及原理解析

文章插图
 
刚刚是因为『一个提案只要被一个Acceptor接受,则该提案的value就被选定了』才导致了出现上面不一致的问题 。因此,我们需要加一个规定:
规定:一个提案被选定需要被半数以上的Acceptor接受
这个规定又暗示了:『一个Acceptor必须能够接受不止一个提案!』不然可能导致最终没有value被选定 。比如上图的情况 。v1、v2、v3都没有被选定,因为它们都只被一个Acceptor的接受 。
最开始讲的『提案=value』已经不能满足需求了,于是重新设计提案,给每个提案加上一个提案编号,表示提案被提出的顺序 。令『提案=提案编号+value』 。
虽然允许多个提案被选定,但必须保证所有被选定的提案都具有相同的value值 。否则又会出现不一致 。
于是有了下面的约束:
P2:如果某个value为v的提案被选定了,那么每个编号更高的被选定提案的value必须也是v 。
一个提案只有被Acceptor接受才可能被选定,因此我们可以把P2约束改写成对Acceptor接受的提案的约束P2a 。
P2a:如果某个value为v的提案被选定了,那么每个编号更高的被Acceptor接受的提案的value必须也是v 。
只要满足了P2a,就能满足P2 。
但是,考虑如下的情况:假设总的有5个Acceptor 。Proposer2提出[M1,V1]的提案,Acceptor2~5(半数以上)均接受了该提案,于是对于Acceptor2~5和Proposer2来讲,它们都认为V1被选定 。Acceptor1刚刚从宕机状态恢复过来(之前Acceptor1没有收到过任何提案),此时Proposer1向Acceptor1发送了[M2,V2]的提案(V2≠V1且M2>M1),对于Acceptor1来讲,这是它收到的第一个提案 。根据P1(一个Acceptor必须接受它收到的第一个提案 。),Acceptor1必须接受该提案!同时Acceptor1认为V2被选定 。这就出现了两个问题:
Acceptor1认为V2被选定,Acceptor2~5和Proposer2认为V1被选定 。出现了不一致 。
V1被选定了,但是编号更高的被Acceptor1接受的提案[M2,V2]的value为V2,且V2≠V1 。这就跟P2a(如果某个value为v的提案被选定了,那么每个编号更高的被Acceptor接受的提案的value必须也是v)矛盾了 。
Paxos算法为什么说是Raft,Zab协议的鼻祖,及原理解析

文章插图
 
所以我们要对P2a约束进行强化!
P2a是对Acceptor接受的提案约束,但其实提案是Proposer提出来的,所有我们可以对Proposer提出的提案进行约束 。得到P2b:
P2b:如果某个value为v的提案被选定了,那么之后任何Proposer提出的编号更高的提案的value必须也是v 。
由P2b可以推出P2a进而推出P2 。
那么,如何确保在某个value为v的提案被选定后,Proposer提出的编号更高的提案的value都是v呢?
只要满足P2c即可:
P2c:对于任意的N和V,如果提案[N, V]被提出,那么存在一个半数以上的Acceptor组成的集合S,满足以下两个条件中的任意一个:
S中每个Acceptor都没有接受过编号小于N的提案 。
S中Acceptor接受过的最大编号的提案的value为V 。
Proposer生成提案为了满足P2b,这里有个比较重要的思想:Proposer生成提案之前,应该先去『学习』已经被选定或者可能被选定的value,然后以该value作为自己提出的提案的value 。如果没有value被选定,Proposer才可以自己决定value的值 。这样才能达成一致 。这个学习的阶段是通过一个『Prepare请求』实现的 。


推荐阅读