paxos made simple
[翻译自 Leslie Lamport 论文http://lamport.azurewebsites.net/pubs/paxos-simple.pdf ,
本文参考http://blog.csdn.net/wuhuaiyu/article/details/72329397,http://blog.csdn.net/sparkliang/article/details/5740882.
修改了一些名词的译法,对于一些长句作出了修改,减少了可能的歧义,使之更加易懂,观迎评论。p2b到p2c的归纳证明部分翻译得我不是很满意。]
0概要
paxos 算法通过日常(plain)英语来描述是简单的(simple)
1 引言
用于实现一个允许错误(fault-tolerant)的分布式系统的Paxos算法被认为是难于理解的,可能因为对许多读者来说原始的表述是一个希腊的故事[5]。实际上,这个算法是最简单最显而易见的分布式一致性算法之一。[5]中的选举(synod)算法的核心是一种一致性算法.下一节会展示这个一致性算法来自于(follows almost unavoidably)我们想要一致性算法需要满足的属性.最后一部分解释了完整的paxos算法,它是通过把易懂的一致性软件(application)用在构建分布式系统的状态机实现(approach)来得到的(obtained)。这种状态机实现应该是著名的,因为它可能是最常被引用的关于分布式系统理论的文章[4]的主题(subject)。
2 paxos 一致性算法
[本文作者注释]
paxos 算法的前提
消息传递异步无序(asynchronous):消息可能丢失,可能重复,可能存在任意长时间的延迟,
节点宕机(fail-stop):节点持续宕机,不会恢复
节点宕机恢复(fail-recover):节点宕机一段时间后恢复,在分布式系统中最常见
网络分化(network partition):网络链路出现问题,将N个节点隔离成多个部分
不存在byzantine failure ,即消息不会被修改,也不存在内容损坏
在fail-recover下,消息必须可以被进程持久化,并且持久化不会出错
[注释结束]
2.1 问题描述
设想一组可以提出提议(values)的process。一致性算法保证所有提出的提议中,只有一个提议会被选择(chosen)。如果没有提出提议,那么将不会有提议被选择。如果一个提议被选择,那么所有process可以学习到(learn the chosen value)这个提议。一致性算法需要的安全性要求是
1) 仅可以选择被提出的提议(proposed value)
2) 仅有一个提议(proposal)会被选择
3) process 不会知晓一个值被选择了,直到这个值确实被选择了
(A process never learns that a value has been chosen unless it actually has been.)
我们将不会试图指明精确的活性(liveness)要求。然而,目标是确保最终某个提出的提议会被选择,并且选择好了一个提议后,aprocess 最终能够习得这个值(learn the value)。
我们为一致性算法划分3个角色(agent),分别是:proposer(提出者),acceptor(批准者)和learners(学习者)表示。实现中,一个process可以扮演多个角色,这里我们不关心从角色到process的映射。假设角色之间用消息(messages)通信。我们采用异步、非拜占庭模型
1)角色以任意的速度操作(operate),可能会因为停机而失效(fail by stopping),可能会重启(restart)。因为所有的角色都可能会在提议被选择后停机(fail),然后重启,因此任何一个解决方案都要求角色必须能够记住(remember)某些信息,从而能在重启后重新载入。
2)消息的投递(deliver)可能会花费任意长的时间,可能会重复或丢失,但是内容不会损坏。
2.2 选择一个值(choosing a value)
最简单的方式是仅有一个acceptor角色。Proposer发送提议(proposal)给这个acceptor,它选择最先收到的提议(proposed value)。尽管简单,但是如果这个acceptor停机了,那么系统就不能继续运行了,这个方案并不能满足要求。【明显的单点问题】
看来我们需要选择另外的方法,我们有多个acceptor角色,aproposer向一组acceptor提出提议。一个acceptor可以接受(accept)该提议,当有足够多的acceptor接受了这个提议时,提议就被选择了。那么需要多少才足够呢?为了保证只有一个决议可以被选择,任何多数派(majority)都满足。因为任意两个多数派至少共同拥有一个相同的acceptor,如果一个acceptor最多只能接受一个值,这就是可行的(it works)。(有一个明显的关于多数派的概括,这个概括存在于许许多多的论文中,明显是从[3]开始的)
假设没有失败(failure)或者消息丢失,即使仅有一个proposer提出了一个提议,我们也希望能选择这个提议。这就导出了下面的要求:
P1. Acceptor必须接受它接收到的第一个提议。
P1. An acceptor must accept the first proposal that it receives
但是该要求会导致一个问题。同时可能有几个proposer提出了几个不同的决议,恰好导致每个acceptor都接受了一个提议,但是没有一个决议是被多数派接受。即使只有两个提议,如果每个都被半数的acceptor接受,单个的acceptor失效也会导致不可能知道到底哪个提议被选择了。(failure of a single acceptor could make it impossible to learn which of the values was chosen)
一个提议要经过多数派的接受才能被选择,这个要求和P1暗示了acceptor必须能够被允许接受多个提议。我们为每个提议分配一个编号来记录不同的提议,因此一个议案由编号和值(value)构成【也就是提议={编号,值}】。为避免混淆,我们要求提议的编号是唯一的。这个取决于实现,现在我们假设可以做到这一点。如果一个提议{n, v}被多数派的接受,那么值v就被选择了。这种情况下,我们称提议(包括其值v)被选择了。
我们允许多个提议被选择(chosen),但是必须保证所有选择的提议包括相同的值(v)。对提议编号归纳(induction),它足以(suffices)保证:
P2.如果一个提议{n, v}被选择,那么每一个编号更高的被选择的提议包含的值都是v。
P2. If a proposal with value v is chosen, then every higher-numbered proposal that is chosen has value v.
因为编号是全序的,P2保证了“只有一个值(value)被选择”这一关键安全属性。提议必须至少被一个acceptor批准才可能被选择。因此只要满足下面的条件,就可以满足P2:
P2a.如果一个提议{n, v}被选择,那么每一个acceptor接受的编号更高的提议包含的值都是v。
P2a. If a proposal with value v is chosen, then every higher-numbered proposal accepted by any acceptor has value v.
我们依然保持P1来确保(ensure)某个提议会被选择。因为通信是异步的,可能有这样的情况,某个acceptor c从没有收到(receive)过任何提议,但多数派已经接受了(accepted)了一个提议{n,v}。 假设这时一个新的proposer醒来(wakeup)并提出了一个更高编号的提议(包含不同的值value)。P1要求c应该接受这个提议,但是这违反了P2A。为了同时保证P1和P2A,我们需要增强P2A:
P2B. 如果一个提议{n, v}被选择,那么此后,任何proposer提出的编号更高提议包含的值都是v。
P2b. If a proposal with value v is chosen, then every higher-numbered proposal issued by any proposer has value v.
因为一个提议必须在被proposer提出后才能被acceptor批准,因此P2B 蕴涵了P2A,P2A蕴涵P2(蕴涵是充分条件的意思)
因此接下来的重点就是论证p2b成立即可
假设某个提议{m,v}已经被选择了,证明任何编号n>M的提议,其value值都是v
[注释
第二数学归纳法
设P(n)是一个与自然数有关的命题,如果:
1°P(1)成立;
2°假设P(n)对于所有满足l<k成立,则P(k)成立;
那么P(n)对所有自然数都成立.
它的理论依据是最小数原理——自然数集的任一非空子集必有一个最小数
数学归纳法的正确性来自Peano公理
需要证明以下结论: 假设编号从m到n-1之间的提议,其value值都是v,证明编号为n的提议的值也是v
注释结束]
如何才能满足P2B呢,让我们来考虑如何证明这个提议持有的值(it holds) 。我们假设某个提议{m, v}被选择,然后说明(show)任何编号n>m的提议的值都是v。对n归纳可以简化证明,在额外的假设下(under the additional assumption)--编号从m到n-1的每个提议值都是v(i..j 表示从i到j的所有整数的集合),我们需要证明编号为n的提议的值是v。对于已被选择(chosen)的编号为m的提议,必定存在一个集合C由接受了这个提议的acceptor多数派组成,结合归纳假设(induction assumption),m被选择这意味着(多数派的交集必非空):
对于一个编号在m到n-1范围内的每个提议都至少C中的一个acceptor接受了它,每一个C中的acceptor都接受了m..(n-1)中的某一个提议,并且任何acceptor接受的编号从m到n-1的提议的值为v。
因为任何由多数派组成的集合S都至少包含C中的一个成员,我们可以得出结论:如果下面p2c的不变性得到了保持,那么编号为n的提议的值是v:
P2C. 对于任意的v和n,如果存在一个由acceptor的多数派组成的集合S,
a) S中没有acceptor接受过编号小于n的议案,或者
b) 所有编号小于n并被S中的所有acceptor接受的提议中,v是编号最大的提议的值。
提议{n, v}才能被提出,
P2c. For any v and n, if a proposal with value v and number n is issued,then there is a set S consisting of a majority of acceptors such that either (a) no acceptor in S has accepted any proposal numbered less than n, or (b) v is the value of the highest-numbered proposal among all proposals numbered less than n accepted by the acceptors in S.
我们可以通过保持P2C中的不变量,来满足P2B。为了保持P2C的不变性,准备提出议案(编号为n)的proposer必须知道所有编号小于n的议案中编号最大的那个,如果存在的话,它已经或将要被acceptor的某个多数派批准。获取已经批准的提议是简单的,但是预知将来可能批准的议案是困难的。Proposer并不做预测,而是提出(extract)一个承诺,永不会有这样的接受(such acceptances)。也就是说,proposer要求acceptor不能批准任何编号小于n的议案。这引出了下面提出提议的算法
1 proposer选择一个新编号n,向some acceptor集合中的所有成员发送请求,并要求回应:
a) 一个永不接受编号小于n的议案的承诺,以及
b) 在它已经接受的所有编号小于n的提议中,编号最大的提议,如果存在的话。
我把这样的请求称为prepare request with number n。
2 如果proposer收到了acceptors中多数派的回应,那么它就可以提出提议{n, v},其中v是所有回应中编号最高的提议的值,或者是proposer选择的任意值,如果acceptor们回应说还没有批准过议案。
一个proposer向一个acceptor集合发送提议(不必是回应proposer初始请求的acceptor集合),我们称之为accept请求。我们已经描述了proposer的算法。那么acceptor呢?它可以接收两种来自proposer的请求: prepare请求和accept请求。Acceptor可以忽略任何请求,而不用担心安全性。因此,我们只需要描述它需要回应请求的情况。任何时候它都可以回应prepare请求,它可以回应accept请求,接受提议,当且仅当它承诺过,换句话讲:
P1A. acceptor可以接受一个编号为n的提议,当它没有回应过一个编号大于n的prepare请求。
P1a. An acceptor can accept a proposal numbered n iff it has not responded to a prepare request having a number greater than n.
P1A蕴含了P1。
现在我们得到了一个完整的算法,它满足我们要求的安全属性——假设议案编号唯一。通过一个小的优化就能得到最终算法。
假设一个acceptor接收到一个编号为n的prepare请求,但是它已经回应了一个编号大于n的prepare请求。于是acceptor就不会接受这个编号为n的prepare请求了,因为它不会接受这个编号为n的提议,所以这个acceptor会忽略(ignore)这个编号为n的prepare请求,它也会忽略包含它已经接受的编号的prepare request.
有了这个优化,acceptor只需要保存它已经批准的最高编号的提议(包括编号和决议),以及它已经回应的所有prepare请求的最高编号。因为任何情况下,都需要保证P2C的不变性,acceptor必须记住这些信息,即使在失效(fails)并重启之后。注意,proposer可以在任何时候的抛弃一个提议并忘记它——只要它永远不会使用相同的编号来提出另一个提议。
结合proposer和acceptor的行为,我们将把算法可以分为两个阶段来执行。
阶段1.
a) Proposer选择一个议案编号n,向acceptor的多数派发送编号为n的prepare请求。
b) Acceptor:如果接收到的prepare请求的编号n大于它已经回应的任何prepare请求,它就回应此请求
---已经接受的编号最高的提议(如果有的话),并承诺不再回应任何编号小于n的议案;
阶段2.
a) Proposer:如果收到了多数acceptor对prepare请求(编号为n)的回应,它就向这些acceptor
发送提议{n, v}的accept请求,其中v是所有回应中编号最高的提议的值,或者是proposer选择的值,
如果全部回应都还没有值。
b) Acceptor:如果收到了提议{n, v}的accept请求,它就批准该议案,除非它已经回应了一个编号大于n的提议。
Proposer可以提出多个提议,只要它遵循上面的算法,它可以在算法的任何时刻放弃一个提议。(这不会破坏正确性,即使在议案被放弃许久后,提议的request请求或者回应消息才到达目标).如果其它的proposer已经开始提出更高编号的议案,那么放弃当前的提议很大可能更好。因此,如果an acceptor忽略一个prepare或者accept请求(因为已经收到了更高编号的prepare请求),它应该(probably)告知proposer放弃提议。这是一个性能优化,不影响正确性。
[注释,证明p2c⇒p2b的过程
我们再来看p2c,实际上p2c规定了每个proposer如何产生一个提案:对于产生的每个提案[Mn,Vn] 需要满足如下条件:
存在一个由超过半数的Acceptor组成的集合S:
要么S中没有Acceptor批准过编号小于Mn的任何提案
要么S中的所有Acceptor批准的所有编号小于Mn的提案中,编号最大的那个提案的value值为Vn
当每个proposer都按照这个规则来产生提案时,就可以保证满足p2b了,接下来我们就使用第二数学归纳法来证明p2b
首选假设提案[M0,V0]被选定了,设比该提案编号大的提案为[Mn,Vn],我们需要证明的就是在p2c的前提下,对于所有的[Mn,Vn],必有Vn=v0
1. 当Mn=M0+1时,如果有这样一编号为M0+1的提案,那么根据p2c,存在一个多数派集合S. 根据S的情况提出了Vn。设S0是批准M0的多数派的acceptors构成的集合,由多数派的性质S0和S的交集非空,所以S中的所有acceptors不能都没批准过编号小于M0+1的提案。 设S中所有Acceptor批准的所有编号小于M0+1的提案中,编号最大的那个提案的编号是X,显然有X<=M0, 设S0和S的交集共有一个acceptor Z, 因为Z 属于S0,所以Z批准的最大编号Y=M0,而Z又属于S,得出X要大于等于Z的最大编号Y即 M0=Y<=X<=M0, 所以 X=M0,
所以此时Vn 的值是M0的值V0
以上是数学归纳的第一步,验证初值成立
2。 根据假设,编号在M0+1到Mn-1区间内的所有提案的value值为V0,需要证明的是编号为Mn的提案的value值
也为V0, 根据p2c,首先同样一定存在一个Acceptor的子集S,且S中的Acceptor已经批准了小于Mn的提案,那么编号为Mn的提案的Value值只能是这个多数集S中编号小于Mn但为最大编号的那个提案的值. 如果这个最大编号落在M0+1到Mn-1区间内,那么Value的值肯定是V0, 如果不落在M0+1到Mn-1的区间内,那么它的编号不可能比M0再小了,肯定就是M0,因为S也肯定会与批准[M0,V0]这个提案的Acceptor集合S0有交集。 而如果编号是M0,那么它的Value值也是V0,由此得证结论
注释结束]
2.3 获知已经被选择的值
Learner必须找到一个被多数acceptor批准的提议,才能知道一个值(value)被选择了。一个显而易见的算法就是,让每个acceptor在批准提议时通知所有的learner,把proposal发给他们。这可以让learner尽快知道被选择的值,但是它要求每个acceptor通知每个learner——需要的消息个数等于learner数和acceptor数的乘积。
基于非拜占庭失败假设,一个learner可以从另一个learner得知被选择的值。我们可以让acceptor将接受情况回应给一个主(distinguished)Learner,它再把被选择的值通知给其它的learner。这增加了一次额外的消息传递,会比前一种不可靠一些,因为主learner可能会失效,但是要求的消息个数仅是learner数和acceptor数的总和。
更一般的,acceptors可以通知多个主(distinguished)Learners,每个主learner都能通知其它所有的learners。主learner越多越可靠,但是通信复杂性会增加
由于消息丢失,可能没有learner知道选择了一个值。Learner可以向acceptor询问批准的提议,但是由于acceptor的失效(failed),可能难以得知多数派是否接收了一个值。这样,learner只能在新的提议被选择时才能知道the value。如果alearner需要知道是否一个值已经被选择了,它可以让aproposer根据上面的算法提出一个新的提议【提出请求就有回应,并且新的提案的决议就是当前选择的决议,这样learner会提到通知】。
2.4 处理流程 progress
很容易构造这样一个场景,两个proposer轮流提出一系列编号递增的议案,但是都没有被选择。Proposerp用提议的编号为n1,并结束阶段1;另外一个proposer q选择了提议编号n2>n1,并结束阶段1。于是p在阶段2的accept请求将被忽略,因为acceptor已经承诺不再批准编号小于n2的议案。于是p再回到阶段1并选择了编号n3 > n2,这又导致q第二阶段的accept请求被忽略;这样一直循环下去。。
为了保证达到最终一致的流程能够结束,必须选择一个主(distinguished)proposer,只有主proposer才能提出提议。如果主proposer和多数acceptor成功通信,并提出一个编号更高的提议,提议将被接受,值会被选择。如果它得知已经有编号更高的议案,它将放弃当前的提议,主proposer最终能选择一个足够大的编号。
如果系统中有足够的组件(proposer,acceptor和网络)能正常工作,通过选择一个主proposer,liveness就能得到满足。Fischer、Lynch和Patterson的著名结论[1]表明:选择主proposer的可靠算法必须使用随机(randomness)或者实时(real time)——例如,使用超时机制(timeout)。然而不管选择成功与否,安全性都能得到保证。
([1]即是FLP不可能定理:在异步通信场景,即使只有一个进程失败,也没有任何算法能保证非失败进程达到一致性)
2.5 实现
Paxos算法[5]假设了一个某些进程(processes)组成的网络(network)。在其一致性算法中,每个process都同时扮演proposer、acceptor和learner的角色。算法选择一个leader,它就是主proposer和主learner。Paxos一致性算法就是上面描述的那个,请求和响应都用普通消息发送(响应会被打上对应提议的编号,以防止混淆)。使用持久化存储来保证acceptor失效后也能记住必要的信息。Acceptor在发送响应前必须持久化存储该响应。
接下来就是描述保证任何两个提议的编号都不相同的机制。proposer从互不相交的集合中选择议案编号,因此两个不同的proposer永远不会提出相同编号的议案。每个proposer都持久化保存(in stable storage)它已经提出的编号最高的提议,并使用一个更高的提议编号来开始阶段1。
3 实现状态机模型
[注释
有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在面向对象的软件系统中,一个对象无论多么简单或者多么复杂,都必然会经历一个从开始创建到最终消亡的完整过程,这通常被称为对象的生命周期。一般说来,对象在其生命期内是不可能完全孤立的,它必须通过发送消息来影响其它对象,或者通过接受消息来改变自身。在大多数情况下,这些消息都只不过是些简单的、同步的方法调用而已。
在描述有限状态机时,状态、事件、转换和动作是经常会碰到的几个基本概念。
状态(State)指的是对象在其生命周期中的一种状况,处于某个特定状态中的对象必然会满足某些条件、执行某些动作或者是等待某些事件。
事件(Event)指的是在时间和空间上占有一定位置,并且对状态机来讲是有意义的那些事情。事件通常会引起状态的变迁,促使状态机从一种状态切换到另一种状态。
转换(Transition)指的是两个状态之间的一种关系,表明对象将在第一个状态中执行一定的动作,并将在某个事件发生同时某个特定条件满足时进入第二个状态。
动作(Action)指的是状态机中可以执行的那些原子操作,所谓原子操作指的是它们在运行的过程中不能被其他消息所中断,必须一直执行下去。
注释结束]
实现分布式系统的一种简单方式就是使用一些客户端向中心服务器发送命令【就是C/S模式了】。服务器可以看作是根据一定顺序执行客户端命令的确定(deterministic)状态自动机。状态机包含当前状态,它读入input作为一个命令然后产生相应的结果,这样它进入到一个新的状态,这个过程叫做一步(a step)。比如,分布式银行系统的客户端可能是出纳员,状态机的状态可能(might)由所有用户的账户余额构成。取款操作通过执行一条状态机命令来完成:减少一个账户余额,输出新旧余额数(当且仅当余额大于取款值)。
使用单个中心服务器的实现是不可靠的,当这个机器fail时,服务fail了。因此我们使用一组服务器,每一个都独立的实现了状态机。因为状态机是确定的(deterministic),如果执行相同的命令序列(same sequence of commands),所有的服务器将会产生同样(the same)的状态序列和输出【非拜占庭模型假设】。客户端发起命令后,可以使用任何服务器对于这个命令的输出。
为了保证所有的服务器执行的是相同的状态机命令序列,我们通过paxos一致性算法执行多个有顺序的相互独立的instance(选择(chose)一个value的过程是一个instance),第i个实例(instance)选择的值(value)就是序列的第i个状态机命令。在算法的每个实例中,每个server都扮演所有的角色(proposer、acceptor和learner)。现在,假设服务器的集合固定,所有的paxos实例都使用相同集合的角色(agents)。
正常操作下,一个服务器被选择为leader,它就是所有的paxos实例(instance)的主proposer(唯一能够提出提议的)。客户端向leader发送命令,leader决定这个命令应该出在命令序列的位置。如果leader决定某个客户端命令应该是第135个命令,它将试图把该命令选择为第135个pasox实例的值,通常都能成功。有可能因为失效(failures)而失败(fail),或者另外的一个服务器相信它也是leader,那个服务器认为第135个instance应该是别的值。但是一致性算法保证最多只能有一个命令能被选择成为第135个paxos instance的值。
Paxos一致性算法的效率(efficienc)的关键在于,提议的value直到阶段2才会被选择。在算法的阶段1结束后,或者提决的值已经确定(determined)了,或者proposer可以提出任何提议。我将描述正常操作下(during normal operation)Paxos状态机实现(implementation)的执行情况。接下来,再讨论可能的错误情况。我会考虑前一个leader失效(failed)、新的leader刚被选择,这时会发生什么情况(系统启动是个特例(specail case),这时还没有提出提议)。
新的leader在paxos一致性算法的所有实例中也是learner,应该知道大部分(most)已经被选择的命令(value)。假设它知道命令1–134、138和139——也就是算法实例1–134、138和139选择的值(后面将看到命令序列中的间隔是如何引起[arise]的)。然后leader执行paxos实例135-137的阶段1和所有大于139的paxos实例(后面会描述如何做到这一点)。假设这些执行的结果将决定paxos实例135和140提议的值,但是让其它paxos实例的提议的值未受到限制(unconstrained)。然后leader为paxos实例135和140执行阶段2,并选择了第135和140个命令。
Leader和其它所有(知道leader知道的所有命令)的服务器,现在可以执行命令1-135。但是不能执行命令138-140(虽然它们也知道),因为命令136和137还没有被选择。Leader也可以把客户端接下来提出的两个命令选为命令136和137。但是我们通过提议一个特殊的"no-op"(不会改变状态机的状态)命令作为136和137,立即填充命令的空缺(fill the gap),(通过执行paxos实例136和137的阶段2来做到这一点)。一旦这些no-op命令被选择,命令138-140就能被执行了。
现在命令1-140已经被选择了。Leader还已经为所有大于140的paxos实例完成了一致性算法的阶段1的操作【注解*】,并可以自由地在这些paxos实例在阶段2中提议任何值。它把客户端的请求下一条命令编号为141,提议它作为实例141的阶段2的值。再把它收到的下一条客户端命令提议为142命令,然后继续下去(and so on)。
【注解*】
对于同一个leader而言,如果它在执行实例i中执行了阶段1,那么后续的执行实例就不需要再次执行阶段1了,而直接执行阶段2,原因如下:
1. 因为它提出的议案编号总是递增的,acceptor必定接受阶段1的prepare请求;
2. 每个实例都是独立运行的paxos算法,互不干扰,决议互相独立;
减少了一个阶段,效率也必定有所提高。
【end*】
在知道提出的命令141被选择之前,Leader可以提出命令142。它提议命令141的过程中它发送的所有的消息可能都丢失了,还可能在其他任何服务器知道(leader提议命令141的)值之前,命令142已经被选择了。 当leader不能收到(fail to receive)它实例141的阶段2的响应时,它将重传这些消息。如果一切顺利,它提出的命令将被选择。然而,它也可能会先失败(fails),这样在已经选择的命令序列中留下了一个间隔。一般来说,假设leader可以提前α个命令——也就是说,在命令1到i被选择之后,它就可以同时提出命令i+1到 i+α。那么最多可以产生由α-1个命令组成的间隔(gap)【容易理解,前面的α-1个命令都失败了】。
新选出的leader要为paxos算法的许多个实例执行阶段1——在上面的场景中,是实例135-137,然后正常执行139之后的所有实例。对所有实例使用相同的提议编号,它可以通过向其他的服务器发送一条短的合理的消息来做到这一点(a single reasonably short message)。在阶段1,仅当acceptor已经收到了一个来自其它proposer的阶段2的消息时,除了简单的OK,它的回应会包含额外的消息,(在上述场景中,仅实例135和140是这样的,因为135和140的阶段1由原来的leader已经完成了)。因此,一般情况下服务器(作为acceptor)可以为所有实例(instance)回应一条(single)合理的短消息。这些许多个实例(instance)的阶段1并不会产生(pose)任何问题。
因为leader的失效和由此引发的选举应该是小概率事件,执行一条状态机命令的实际(effective cost)开销——达到对命令/值的一致性——仅仅是一致性算法的阶段2的开销。能够被展示出来,为了达成一致,在允许失效的情况下(in the presence of faults),在所有的同类(一致性)算法中, paxos一致性算法的阶段2具有最小可能的开销[2]。因此paxos算法在本质上是最佳的(optimal)。
对系统正常(normal)操作的讨论假设一直存在单个(single)leader,除去(except)在当前leader失效和选举新leader之间的一小段时间。在异常环境中,leader选择可能失败。如果没有服务器被选为leader,那么没有新命令会被提议。如果多个服务器都认为自己是leader,在同一个算法实例中,它们将都能提出提议,这可能会导致所有的提议都不能被选择。然而,安全属性是保持的(preserved)——两个不同的服务器永远不会在第i个状态机命令的值上有分歧(disagree)。选择单一的leader只是为了确保流程更快(progress)。
如果服务器的集合会变动,那么必须有某种方法能够确定哪些服务器执行的是算法的哪个实例。最简单的做法就是让状态机自己做到。当前的服务器集合可以作为状态的一部分,并能被普通的状态机命令修改。,通过(执行i+α命令的)服务器集合由第i个状态机命令执行后的状态确定,我们可以让leader提前同时执行α个命令。这允许(permit)了一个任意复杂算法的简单实现。
[注释
http://en.wikipedia.org/wiki/Paxos_algorithm
http://www.wikilib.com/wiki/Paxos%E7%AE%97%E6%B3%95
【还有两个重要的问题就是如何选举leader,以及server间数据的同步,可以参看zookeeper的实现】
]
References
[1] Michael J. Fischer, Nancy Lynch, and Michael S. Paterson. Impossibility
of distributed consensus with one faulty process. Journal of the ACM,
32(2):374–382, April 1985.
[2] Idit Keidar and Sergio Rajsbaum. On the cost of fault-tolerant consensus
when there are no faults—a tutorial. TechnicalReport MIT-LCS-TR-821,
Laboratory for Computer Science, Massachusetts Institute Technology,
Cambridge, MA, 02139, May 2001. also published in SIGACT News
32(2) (June 2001).
[3] Leslie Lamport. The implementation of reliable distributed multiprocess
systems. Computer Networks, 2:95–114, 1978.
[4] Leslie Lamport. Time, clocks, and the ordering of events in a distributed
system. Communications of the ACM, 21(7):558–565, July 1978.
[5] Leslie Lamport. The part-time parliament. ACM Transactions on Computer Systems, 16(2):133–169, May 1998.
11