Paxos算法是分布式系统中常用的一个保持系统一致性的算法,由美国计算机科学家Leslie B. Lamport提出。原文链接。 今天特意学习了一下Paxos的原理,为防忘记,记录下来。(看了的东西没过几天会忘的精光 T_T 。。)
1. 算法要解决的问题
在一个系统中有多个独立的提案者,他们的地位是平等的,都可以就某一问题提出自己的提案(proposal),系统也不存在一个居中的仲裁者来决定采纳哪个。那么如何保证系统最终采纳一个唯一的提案,并且使得每个提案者都获悉这个被采纳的提案呢。Paxos算法要解决的就是这个问题。
一个常用的场景是分布式系统中的leader选举。
2. 算法描述
2.1 三个抽象角色
Proposer 提案者
负责提出议案,并告知acceptorAcceptor 临时决议者
暂决并暂存提案,并为Proposal的prepare阶段提供支持Learner 状态检查者
检测系统是否决策出一个提案(原文意思应该为获悉决策结果,感觉译为检测更符合他的行为),并告知其他learner
这三个角色都是抽象的,不是一个单独的进程。
2.2 何为选定一个提案?
原文的定义:
The value is chosen when a large enough set of acceptors have accepted it. How large is large enough? To ensure that only a single value is chosen, we can let a large enough set consist of any majority of the agents.
即系统的大部分acceptor接受了这个议案,可以将大部分定义为过半数。
2.3 算法过程
Phase 1. (a) A proposer selects a proposal number n and sends a prepare request with number n to a majority of acceptors.(b) If an acceptor receives a prepare request with number n greater than that of any prepare request to which it has already responded, then it responds to the request with a promise not to accept any more proposals numbered less than n and with the highest-numbered proposal (if any) that it has accepted.
Phase 2. (a) If the proposer receives a response to its prepare requests (numbered n) from a majority of acceptors, then it sends an accept request to each of those acceptors for a proposal numbered n with a value v, where v is the value of the highest-numbered proposal among the responses, or is any value if the responses reported no proposals.(b) If an acceptor receives an accept request for a proposal numbered n, it accepts the proposal unless it has already responded to a prepare request having a number greater than n.
阶段一: (a)一个Proposer选取一个数字 n 作为一个提案的编号,然后向大部分acceptor发送一个prepare request 。(b) 如果一个acceptor收到一个prepare request ,提案的编号为n,并且n大于任何他所回复过的提案的编号,那么他将返回他已经接受了的最大编号的提案,并且承诺不会再接受任何编号小于n的提案。
阶段二:(a) 当Proposer收到来自大部分acceptor的回复,他将向大部分acceptor发送一个accept request, 请求acceptor接受这个编号为n的提案。如果acceptor回复了所接受了的最大编号的提案,那么编号为n的提案的内容应该设置为Proposer所收到的编号最大的提案的内容,如果acceptor没有返回提案,那么由Proposer自己决定提案的内容。(b)当一个acceptor收到一个提案的编号为n的accept request ,如果该acceptor之前没有回复过一个编号大于n的提案,那么接受该提案。
阶段一和阶段二是主要的部分,在accept一个提案之后可以通知Learner检查一下系统是否选定了一个提案。如果已经选定就可以终止了。
3. 算法证明
要证明的问题有俩个:
- 1.该方法确实会使得系统达成一致。
- 2.当达成一致后,后续的proposal不会影响系统状态。即一旦达成一致后,后续的proposal都不可能改变系统已经达成的对某一问题的决议结果。
3.1 先论述第一个问题:
首先假设 系统不会进入原文 2.4 所描述的困境。那么首先多个Proposer提出提案,最初acceptor都未接受过提案,因此在最初肯定有一个或多个Proposer自行决定了提案的内容。(在阶段一可能有某些提案被acceptor丢弃)现在进入阶段二,Proposer请求大部分acceptor接受自己的提案。因为已经假设不会进入原文2.4描述的困境,那么阶段二之后肯定存在了已经接受了提案的acceptor。此时Learner检查系统是否已经选定一个提案,若已存在某一提案被大部分acceptor接受,那么不再提议新的提案,并将选定的提案告知其他Learner,Paxos过程结束。
若未选定,那么整个系统中肯定存在一个编号最大的提案,那么根据阶段二中描述的提案内容的决定方法,在后续的提议中这个编号最大的提案的内容将被不断扩散。(注意不是提案被扩散,只是其内容,一个提案应该由内容和其编号构成。) 可想而知,经过几轮提议之后该内容肯定会被大部分acceptor所接受。
实质上是三个过程:首先大家都提出一个提案,然后从中选择一个编号最大的提案,最后扩散这个提案的内容。扩散的时候不断赋予新的编号(编号是递增的)。
原文对于原文2.4所描述问题的解决方法是系统中设置一个Leader,只能由Leader提出proposal。这样确实解决了2.4描述的困境,不过私以为与最初描述的问题不符了。对此个人提出的解决办法是,将acceptor承诺不再接受编号小于n的提案改为在一段时间内不再受理新的prepare request,因此会使得一部分acceptor在某一时间内被一个proposer所独占,避免了2.4所描述的竞争囧态。
3.2 第二个问题证明
在之前已经论述了系统肯定会在某一个时刻达成共识。假设这个被选定的提案的编号为m 。现在假设编号 n-1的提案与编号m的提案具有相同的内容(n>m),证明编号为n的提案也具有相同的内容。(数学归纳法)
由于编号为n-1的提案被系统所选定,那么存在过半的acceptor接受了这个提案。现在产生提案n, 首先询问超半数的acceptor,acceptor返回已经接受了的编号最大的提案。因为过了半数,因此在返回的提案中肯定存在编号为n-1的提案,毫无疑问,该提案是所有返回的提案中编号最大的。那么新产生的编号为n的提案的内容设置为编号为n-1的提案的内容。然后发出accept request, 请求acceptor接受这个新的编号为n的提案。因为编号为n的提案的内容与编号为n-1的提案的内容一致,而n-1又与编号为m的提案的内容一致。所以整个系统所达成的共识并没有改变,反而增强了。
在假设部分并没有假设编号n-1的提案被系统选定,其实是被系统选定了的。令n=m+1,那么n-1即为m, 推得编号n的提案的内容也是被系统选定的内容。
Acceptor会舍弃编号小于已经接受的最大编号的提案,因此即使有多个Proposer,也可以保证提案的编号是不断变大的,可能不连续,但没影响。
3.3 为什么Acceptor要承诺不再接受编号小于n的提案?
To maintain the invariance of P2c, a proposer that wants to issue a proposal numbered n must learn the highest-numbered proposal with number less than n, if any, that has been or will be accepted by each acceptor in some majority of acceptors.Learning about proposals already accepted is easy enough; predicting future acceptances is hard.
这是原文的解释,即保证后续的proposal 不会改变已经选定的提案的内容,后续的proposal的内容应该优先设置为acceptor返回的编号最大的proposal的值(提案的内容),但是编号最大的提案可能已经被acceptor所接受,也可能将要被acceptor所接受。对于“将要”这种情况太难操作,预测未来是困难的,因此规定Acceptor需作出不会接受编号小于n的提案的承诺。
若出现编号大于n的提案仍然需要接受,因为此时可以认为编号为n的提案是过时的提案,可以被舍弃。
这篇博客是在原文的基础上写的,算是一个读后感,原文是循序渐进的,讲述了算法的不断完善的递进过程。建议先看原文。