paxos made simple

[ 翻译自 Leslie Lamport 论文

http://lamport.azurewebsites.net/pubs/paxos-simple.pdf  ,

https://www.microsoft.com/en-us/research/wp-content/uploads/2016/12/paxos-simple-Copy.pdf

另外一篇翻译文章  https://segmentfault.com/a/1190000037628341]

0概要

paxos 算法通过日常(plain)英语来描述是简单的(simple)

1 引言

用于实现一个允许错误(fault-tolerant)的分布式系统的Paxos算法被认为是难于理解的,可能因为对许多读者来说原始的表述是一个希腊的故事[5]。实际上,这个算法是最简单最显而易见的分布式一致性算法之一。[5] (注解:paxos第一篇论文)中的选举(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 问题描述

假设有一组进程(processes), 每个进程都可以提出提议(propose values)。一致性算法保证所有提出的提议(valus)中,只有一个提议(one value)会被选择(chosen)。如果没有提出提议(proposed),那么将不会有提议被选择。如果一个提议被选择,那么所有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.)

译者注:

这个问题的背景可以追溯到,分布式为什么要诞生?  因为如果不分布式 ,单机的话存在单点问题,可靠性缺乏保证,一方面是计算的单点,另外一方面是存储的单点.  所以需要多台机器和对应的存储,这些server和存储组成一个整体, 那么问题就来了?  client 随机向任意一个server发起调用,有如下问题
       1. 如何判断第一个指令应该给哪个server接受的客户端指令?

2. 引入了这个决策后, 决策的结果,存储在哪, accepter挂掉了怎么办?

第一问题,本文就是解答这个问题的. 第二个问题的答案在"learner选择这一节"译者注里给出,

其次才是指令本身的计算和结果存储的问题, 机器挂掉后,数据是否丢失的问题? 读怎么读的问题? 各server指令能否乱序执行(后到的先执行,完全取决于是否占用同样的锁,同样的锁必须顺序,否则可以乱序,但关键是如果前面的命令你都不知道,你如何知道是否加同一个锁) ? 多个计算处于同一个事务怎么办? 这些问题都是后续问题了,其他文献会解答,先不扯开.

我们将不会试图指明精准的活性(liveness)要求。然而,目标是确保最终某个提出的提议会被选择,并且选择好了一个提议后,进程(process)最终能够习得这个值(learn the value)。

我们让三类代理(agent)来执行这个一致性算法中的三个角色:提议者(proposers)、接受者(acceptors)以及学习者(learners)。在实际实现中,一个独立的进程可以充当不止一个代理,但是从代理到进程之间的映射关系不是我们这里关注的重点。

假设角色之间用消息(messages)通信。我们采用异步、非拜占庭模型

* 角色以任意的速度运行(operate),可能会因为停机而失效(fail by stopping),可能会重启(restart)。因为所有的角色都可能会在提议被选择后停机(fail), 然后重启,因此任何一个解决方案都要求角色必须能够记住(remember)某些信息,从而能在重启后重新载入。

* 消息的投递(deliver)可能会花费任意长的时间,可能会重复或丢失,但是内容不会损坏。

2.2 选择一个值(choosing a value) 

最简单的方式是仅有一个acceptor角色。Proposer发送提议(proposal)给这个acceptor,它选择最先收到的提议(proposed value)。尽管简单,但是如果这个acceptor停机了,那么系统就不能继续运行了,这个方案并不能满足要求。【明显的单点问题】

所以,让我们来尝试选定值的另一种方法吧。不再是单一的接受者(acceptor),我们现在尝试使用多个接受者代理(acceptor agent)的方式。一个提议者(proposer)将一个提议的值发送给一群接受者。一个acceptor可以接受(accept)该提议,当有足够多的acceptor接受了这个提议时,提议就被选择了。那么需要多少才足够呢?为了保证只有一个决议可以被选择,任何多数派(majority)都满足。因为任意两个多数派至少共同拥有一个相同的acceptor,如果一个acceptor最多只能接受一个值,这就是可行的(it works)。(有一个明显的关于多数派的概括,这个概括存在于许许多多的论文中,明显是从[3]开始的)

假设没有失败(failure)或者消息丢失,即使仅有一个proposer提出了一个提议,我们也希望能选择这个提议。这就导出了下面的要求:

P1.  Acceptor必须接受(accept)它接收到的第一个提议。( P1. An acceptor must accept the first proposal that it receives)

但是该要求会导致一个问题。同时可能有几个proposer提出了几个不同的决议,恰好导致每个acceptor都接受了一个提议,但是没有一个决议是被多数派(majority)接受。即使只有两个提议,如果每个都被半数的acceptor接受,单个的acceptor失效(failure)也会导致不可能知道到底哪个提议被选择(chosen)了(译者注解: 一个失效就导致达不到半数)。

选择 [译者 新增的二级目录]

译者注: 选择这个概念很重要,是对整体而言的,大多数.  对单个角色  proposer : 1. prepare 2. 提议  acceptor: 接受 , 批准  learner:  学习

一个提议要经过多数派的接受才能被选择(chosen),这个要求和P1暗示了acceptor必须能够被允许接受多个提议。我们为每个提议分配一个编号来记录不同的提议,因此一个议案由编号和值(value)构成【也就是提议={编号,值}】。为避免混淆,我们要求提议的编号是唯一的。这个取决于实现 ( 译者注: 参考 zoonkeeper  ,比较关键 ),现在我们假设可以做到这一点。如果一个提议{n, v}被多数派(majority)的接受,那么值v就被选择(chosen)了。这种情况下,我们称提议(包括其值v)被选择(chosen)了。

[译者注解:

下面几段其实都是在被选择的前提下分析, 先设一个结论A,然后分析如何让这个结论成立,提出一个什么新的结论B.  让后进一步分析结论B成立的条件 ]

我们可以允许多个提案被选定,但是必须保证所有被选定的提案拥有一样的值。结合提案编号归纳推理(By induction on the proposal number),,只要保证以下(结论)就够了(it suffices to guarantee):

P2.如果一个提议(proposal){n, v}被选择(chosen),那么每一个编号更高的被选择的提议的值是v。       ( P2. If a proposal with value v is chosen, then every higher-numbered proposal that is chosen has value v. has value v 翻译为 拥有的值 =v)

因为编号是完全有序(totally ordered)的,P2保证了“只有一个值(value)被选择”这一关键安全属性。提议必须至少被一个acceptor批准才可能被选择。所以想要满足(satisfy)P2,只要满足(satisfying)(下面的结论) :

P2a. 如果一个提议{n, v}被选择(chosen),那么每一个acceptor接受的编号更高的提议的值都是v。( P2a. If a proposal with value v is chosen, then every higher-numbered proposal accepted by any acceptor has value v.)

[译者注: p2a 里的 "每一个accepter接受" 是 p2里的 "被选择" 的一种充分条件 ,某种意义上是换句话表达 . 这也是本文的撰写思路, 用后面的结论层层来保证前面的结论成立 ]

我们依然保持P1来确保(ensure)某个提议会被选择。因为通信是异步的,可能有这样的情况,某个接受者(acceptor)c 从没有收到(receive)过任何提议,但多数派已经接受了(accepted)了一个提议{n,v}。 假设这时一个新的proposer故障恢复(wakeup)并提议了一个更高编号的提议(包含不同的值value ) 。P1规则要求接受者(acceptor)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.)

译者注: P2A 里是"提出"是P2B里的提出的

译者注: 该结论,用数学符号表达就是:   提议{m, v}被选择 (数学符号表达里的m 其实就是p2B里的n ) ,任何编号n>m的提议的值都是v (数学符号表达里n 就是 p2B 里的更高提议)

因为一个提议必须在被proposer提出后才能被acceptor批准,因此P2B 蕴涵了P2A(P2b implies P2a),P2A蕴涵P2(蕴涵是充分条件的意思) ( which in turn implies P2.)

[译者注解

因此接下来的重点就是论证p2b成立即可, 假设某个提议{m,v}已经被选择了,证明任何编号n>M的提议,其value值都是v

第二数学归纳法

设P(n)是一个与自然数有关的命题,如果:

1°P(1)成立;

2° 假设P(n)对于所有满足l<k成立,则P(k)成立;

那么P(n)对所有自然数都成立.

它的理论依据是最小数原理——自然数集的任一非空子集必有一个最小数

数学归纳法的正确性来自Peano公理

需要证明以下结论:

假设 {m, v} 被选择, 证明编号为n的提议的值也是v

注释结束]

接受 [ 副标题 译者注 ]

如何才能满足P2B 呢 [ 译者注: 即让P2B结论成立 ],让我们来考虑如何证明这个提议的值就是v(it holds) 。(译者注: P2B 用 数学形式表达 即)  我们假设某个提议{m, v}被选择(译者注: (数学符号表达里的m 其实就是p2B里的n ) ,然后证明(show)任何编号n>m的提议的值都是v (译者注: 数学符号表达里n>m 就是 p2B 里的编号更高提议)。对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,如果一个编号为 n 且拥有值 v 的提案被提议,则存在一个由大多数接受者组成的集合 S 满足这里其中一个条件:

a) 集合S中所有acceptor都没有接受过编号小于n的议案,或者

b)  (如果有接受过) 所有编号小于n并被集合S中的所有acceptor接受的提议中,v是编号最大的提议的值。 (译者注 用数学符号表达即 即  x < n ,   acceptedValue(max(x)) = 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中的不变量,来满足P2B。为了保持P2C的不变性,准备提出议案的proposer必须知道所有编号小于n的议案中编号最大的那个[译者注: P2C 讲的是接受, 因为先有提交后有 接受, 自然要导出"提交"的结论,用于满足P2C ],如果存在的话,它已经或将要被acceptor的某个多数派批准。获取已经批准的提议是简单的,但是预知将来可能批准的议案是困难的。Proposer并不做预测,而是提出(extract)一个承诺,永不会有这样的接受(such acceptances)。也就是说,proposer要求acceptor不能批准任何编号小于n的议案。这引出了下面提出提议的算法 [译者注: 终于到 提议的 流程了 ]

1 proposer选择一个新编号n,向some acceptor集合中的所有成员发送请求,并要求acceptor回应:

a) 一个永不接受编号小于n的议案的承诺,以及

b) 在它已经接受的所有编号小于n的提议中,编号最大的提议,如果存在的话。

( 译者注 用数学符合表达即 即 returnV = acceptValueOfMax( acceptedN  ) )

我把这样的请求称为prepare request with number n。

2 如果proposer收到了acceptors中多数派的回应,那么它就可以提出提议{n, v},其中 如果有批准过, v=所有回应中编号最高的提议的值,或者 如果acceptor们回应说还没有批准过议案, v= proposer选择的任意值(译者注: 这个值作为proposer提案的值). ( 译者注 用数学符合表达即 即 v = acceptedValueOfMaxN == null? numOfProposer : acceptedValueOfMaxN )

一个proposer向一个acceptor集合发送提议(不必是回应proposer初始请求的acceptor集合),我们称之为accept请求。我们已经描述了proposer的算法。那么acceptor呢?它(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 ( 译者注: 蕴含 值 充分条件 ,显而易见,  P1A 可以证明出 P1)。

现在我们得到了一个完整的算法,它满足我们要求的安全属性—— 假设议案编号全局唯一。通过一个小的优化就能得到最终算法。

假设一个acceptor接收到一个编号为n的prepare请求,但是它已经回应了一个编号大于n的prepare请求。于是acceptor就不会接受这个编号为n的prepare请求了,因为它不会接受这个编号为n的提议,所以这个acceptor会忽略(ignore)这个编号为n的prepare请求,它也会忽略包含它已经接受的编号的prepare request.

存储数据结构 [ 译者新增的副标题]

有了这个优化,acceptor只需要保存它已经批准的最高编号的提议(包括编号和决议),以及它已经回应的最高编号。因为任何情况下,都需要保证P2C的不变性,acceptor必须记住这些信息,即使在失效(fails)并重启之后。注意,proposer可以在任何时候的抛弃一个提议并忘记它——只要它永远不会使用相同的编号来提出另一个提议。

完整决议流程 [ 译者新增的副标题]

结合proposer和acceptor的行为,我们将把算法可以分为两个阶段来执行。

阶段1.

a) Proposer选择一个议案编号n,向acceptor的多数派发送编号为n的prepare请求。

b) Acceptor:如果接收到的prepare请求的编号n大于它已经回应的任何prepare请求,它就回应此请求

---已经接受的编号最高的提议(如果有的话),并承诺(promise)不再回应任何编号小于n的议案;

阶段2.

a) Proposer:如果收到了多数acceptor对prepare请求(编号为n)的回应,它就向这些acceptor

发送提议{n, v}的accept请求,其中v是所有回应中编号最高的提议的值,或者是proposer选择的值,

如果全部回应都还没有值。

b) Acceptor:如果收到了提议{n, v}的accept请求(proposer promise accept requset),它就批准(accept) [译者注 wiki 上 用了accepted一词 ,用于区别proposer promise accept请求  ] 该议案,除非它已经回应了一个编号大于n的提议。

译者注, 基于上面的阶段1,阶段2,和本文开头的"选择"的概念, 补充流程图. maxN是回应过的序号, acceptN是接受的序号

译者注: wiki上的时序图.  竖线上的X代表接受并处理.

wiki上的异常流程时序图 

Proposer可以提出多个提议(multiple proposals),只要它遵循上面的算法(algorithm),它可以在算法的任何时刻放弃一个提议。(这不会破坏正确性,即使在议案被放弃许久后,提议的request请求或者回应消息才到达目标). 如果其它的proposer已经开始提出更高编号的议案,那么放弃当前的提议很大可能更好。因此,如果acceptor忽略一个prepare或者accept请求(因为已经收到了更高编号的prepare请求),它应该(probably)告知proposer放弃提议, 这是一个性能优化,不影响正确性。

2.3 Learner获知已经被选择的值

  Learner被acceptor通知

Learner必须找到一个被多数acceptor批准的提议,才能知道一个值(value)被选择了。一个显而易见的算法就是,让每个acceptor在批准提议时通知所有的learner,把proposal发给他们。这可以让learner尽快知道被选择的值[译者注: learner通过大多数判断来确定这个值是否是被选择的],但是它要求每个acceptor通知每个learner——需要的消息个数等于learner数和acceptor数的乘积。

Learner优化  [ 译者新增的副标题]

基于非拜占庭失败假设,一个learner可以从另一个learner得知被选择的值。我们可以让acceptor将接受情况回应给一个主(distinguished) Learner,它再把被选择的值通知给其它的learner。这增加了一次额外的消息传递,会比前一种不可靠一些,因为主learner可能会失效,但是要求的消息个数仅是learner数和acceptor数的总和。

更一般的,acceptors可以通知多个主(distinguished)Learners,每个主learner都能通知其它所有的learners。主learner越多越可靠,但是通信复杂性会增加

Learner消息丢失和主动获取/重试  [ 译者新增的副标题]

由于消息丢失,可能没有learner知道选择了一个值。Learner可以向acceptor询问批准的提议,但是由于acceptor的失效(failed),可能难以得知多数派是否接收了一个值。这样,learner只能在新的提议被选择时才能知道the value。如果learner需要知道是否一个值已经被选择了,它可以让proposer根据上面的算法提出一个新的提议【译者注: 提出请求就有回应,并且新的提案的决议就是当前选择的决议,这样learner会提到通知】。[译者注:  zk中增加了轮的概念,每一轮 ]

译者注: 
     回答本文最上面的译者提出的问题.

问: 决策的结果,存储在哪, accepter挂掉了怎么办?
             答:  决策的本身其实存储在半数的accepter里. 虽然决策超过半数就够了,但是为了可靠性,最好需要超过+1

2.4 处理流程(progress)

活锁  [ 译者新增的副标题]

很容易构造这样一个场景,两个proposer轮流提出一系列编号递增的议案,但是都没有被选择。Proposer p用提议的编号为n1,并结束阶段1; 另外一个proposer q选择了提议编号n2>n1,并结束阶段1。于是p在阶段2的accept请求将被忽略,因为acceptor已经承诺不再批准编号小于n2的议案(详见 提出议案 部分,要求acceper做的工作 )。于是p再回到阶段1并选择了编号n3 > n2,这又导致q第二阶段的accept请求被忽略;这样一直循环下去。[译者注 这就是paxos 活锁]

为了保证达到最终一致的流程能够结束,必须选择一个主(distinguished) proposer,只有主proposer才能提出提议。如果主proposer和多数acceptor成功通信,并提出一个编号更高的提议,提议将被接受,值会被选择。如果它得知已经有编号更高的议案,它将放弃当前的提议,主proposer最终能选择一个足够大的编号。[译者注 这里的"必须" 其实不必须, 活锁不是必然会发生, 选主可以降低概率,但不必须, 详见 本文"实现"一章中的"leader作用和leader冲突 "一节 所以这个选主算法可以比较简单,可重复. {高阶}更有意思的是用简单选主算法启动paxos算法来真正的选主, 进一步可以确定zk中那个是leader,然后跑后续的paxos算法,变成有主的multi paxos, 哪怕leader挂掉后,还能恢复存储 ]

如果系统中有足够的组件( proposer,acceptor 和网络 )能正常工作,通过选择一个主proposer ,活性(liveness) [6] 就能得到满足。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 实现状态机模型

译者注释: 这里的状态机其实是广义上的状态机, 指的是任何有状态的系统. 而不是传统程序员理解的狭义的状态机. 通过下文的文字就能理解 "状态机的状态可能(might)由所有用户的账户余额构成。"

[ 译者注释

有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在面向对象的软件系统中,一个对象无论多么简单或者多么复杂,都必然会经历一个从开始创建到最终消亡的完整过程,这通常被称为对象的生命周期。一般说来,对象在其生命期内是不可能完全孤立的,它必须通过发送消息来影响其它对象,或者通过接受消息来改变自身。在大多数情况下,这些消息都只不过是些简单的、同步的方法调用而已。

在描述有限状态机时,状态、事件、转换和动作是经常会碰到的几个基本概念。

状态(State)指的是对象在其生命周期中的一种状况,处于某个特定状态中的对象必然会满足某些条件、执行某些动作或者是等待某些事件。

事件(Event)指的是在时间和空间上占有一定位置,并且对状态机来讲是有意义的那些事情。事件通常会引起状态的变迁,促使状态机从一种状态切换到另一种状态。

转换(Transition)指的是两个状态之间的一种关系,表明对象将在第一个状态中执行一定的动作,并将在某个事件发生同时某个特定条件满足时进入第二个状态。

动作(Action)指的是状态机中可以执行的那些原子操作,所谓原子操作指的是它们在运行的过程中不能被其他消息所中断,必须一直执行下去。

注释结束]

实现分布式系统的一种简单方式就是使用一些客户端向中心(central)服务器发送命令【就是C/S模式了】。服务器可以看作是根据一定顺序执行客户端命令的确定(deterministic)状态自动机。状态机包含当前状态,它读入input作为一个命令然后产生相应的结果,这样它进入到一个新的状态,这个过程叫做一步(a step)。比如,分布式银行系统的客户端可能是出纳员,状态机的状态可能(might)由所有用户的账户余额构成。取款操作通过执行一条状态机命令来完成:减少一个账户余额,输出新旧余额数(当且仅当余额大于取款值)。

使用单个中心服务器的实现是不可靠的,当这个机器fail时,服务fail了。因此我们使用一组服务器 [译者 分布式就出现了,CAP中P有了] ,每一个都独立的实现了状态机。因为状态机是确定的(deterministic),如果执行相同的命令序列(same sequence of commands),所有的服务器将会产生同样(the same)的状态序列和输出【非拜占庭模型假设】。客户端发起命令后,任何服务器可以响应并创建输出(output), 客户端可以使用这个输出。

为了保证所有的服务器执行的是相同的状态机命令序列,我们通过paxos一致性算法执行多个有顺序的相互独立的instance(选择(chose)一个value的过程是一个instance) [ 译者注 后人优化演进成了 multi Paxos,先选主,只有一个proposal,一个accepter,然后主来执行和同步指令,确保各个learner时序一致],第i个实例(instance)选择的值(value)就是序列的第i个状态机命令。在算法的每个实例中,每个server都扮演所有的角色(proposer、acceptor和learner)。现在,假设服务器的集合固定(fixed),所有的paxos实例都使用相同集合的角色(agents)。

leader作用和leader冲突 [ 译者 新增的二级目录 ]

正常操作下,一个服务器被选择为leader,它就是所有的paxos实例(instance)的主proposer( 唯一能够提出提议的[译者注98, 本文论文这里提到的leader尽量唯一但不强求,  提交议案时需要进行两阶段的提交. ] [与现在的zab/raft区别是, zab/raft的leader都是先选主且必须唯一, 且后续提交时仅一阶段即可] )。

客户端向leader [ 译者注99: 即主(distinguished) proposer ]发送命令,leader 决定每个命令的时序。如果leader决定第135序号 [译者注100: 这里的序号是状态机命令序号 和 一次paxos过程中的不同proposer的全局序号是两个层次上的概念]的命令应该是某个客户端的命令A,它将试图把该命令选择为第135个pasox实例的值,通常都能成功。

有可能因为失效(failures)而失败(fail),或者另外的一个服务器相信它也是leader[译者注101: 见上面译者注里与现在zab/raft的区别解答 ],那个服务器认为第135个instance应该是别的值。但是一致性算法保证最多只能有一个命令能被选择成为第135个paxos instance的值。[ 译者注102: 同一个状态机"序号"并发提交, 只会选择一个.  这里面用状态机"序号"来确定一个paxos过程, "状态机序号"和前面paxos算法的序号的区别详见译者注100  ]

Paxos一致性算法的效率(efficiency)的关键在于,提议的value直到阶段2才会被选择。在算法的阶段1结束后,或者提决的值已经确定(determined)了,或者proposer可以提出任何提议。

我将描述正常运行下(during normal operation) Paxos状态机实现(implementation)的执行情况。

异常情况之leader失效 [ 译者 新增的二级目录 ]

接下来,再讨论可能的异常情况(what can go wrong)。我会考虑前一个leader失效(failed)、新的leader刚被选择,这时会发生什么情况(系统启动是个特例(specail case),这时还没有提出提议)。

提案同步[ 译者 新增的三级目录 ]

新的leader在paxos一致性算法的所有实例中也是learner,应该知道大部分(most)已经被选择的命令(value)。假设它知道1号至134号命令,第138号命令和第139号命令[ 译者注: 没有 135,136,137号提案结果 ]——也就是算法实例1–134、138和139选择的值(后面将看到命令序列中的间隔[gap]是如何引起[arise]的)。[译者新起一段]

然后(新)leader执行paxos实例135-137的阶段1和所有大于139的paxos实例(后面会描述如何做到这一点)。假设这些执行的结果将决定paxos实例135号和140号提议的值,但是让其它paxos实例的提议的值未受到限制(unconstrained)。然后(新)leader为paxos实例135号和140号执行阶段2,并选择了第135号和140号个命令 [ 译者注: 这个过程就是新leader同步老leader提案结果的过程. 详见"2.3 Learner获知已经被选择的值" 这大段最后一句话及译者注解]。

提案跳号补全/ 重新提交议案 [ 译者 新增的三级目录 ]

Leader和其它所有(知道leader知道的所有命令)的服务器,现在可以执行命令1-135。但是不能执行命令138-140(虽然它们也知道),因为第136号和137号命令还没有被选择,[ 译者注: 两个命令只要不存在互斥, 该数据库可以并发的进行多个paxos实例, 所以会有跳号的现象, 138已经被选择,而136号还没有被选择出来]。Leader也可以把客户端接下来提出的两个命令选为命令136号和137。但是我们通过提议一个特殊的"no-op"(不会改变状态机的状态)命令作为136和137,立即填充命令的空缺(fill the gap),(通过执行paxos实例136和137的阶段2来做到这一点)[译者注: 详见"2.3 Learner获知已经被选择的值" 最后一句话及译者注解]。一旦这些no-op命令被选择,命令138-140就能被执行了。[译者注150: 还有一种方式避免串行,就是模仿mvcc的事务的行锁/间隙锁机制. 加同样锁的串行,其他的可以随意 ]

现在命令1-140已经被选择了。Leader还已经为所有大于140的paxos实例完成了一致性算法的阶段1的操作【注解*】,并可以自由地在这些paxos实例在阶段2中提议任何值。它把客户端的请求下一条命令编号为141,提议它作为实例141的阶段2的值。再把它收到的下一条客户端命令提议为142命令,然后继续下去(and so on)。

跳号间隔产生原因[ 译者 新增的三级目录 ]

在知道提出的命令141被选择之前,Leader可以提出命令142。它提议命令141的过程中它发送的所有的消息可能都丢失了,还可能在其他任何服务器知道(leader提议命令141的)值之前,命令142已经被选择了。第141个实例, 当leader无法收到(fail to receive)响应,以至于无法进入阶段2,它将重传这些消息。如果一切顺利,它提出的命令将被选择。然而,它(141)也可能会先失败(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)合理的短消息[译者注: 合理的短消息里包含了这是那一轮实例信息即可,有点multi paxos的味道,但作者并没有说太多.]。这些许多个实例(instance)的阶段1并不会产生(pose)任何问题。

因为leader的失效和由此引发的选举应该是小概率事件,执行一条状态机命令的实际(effective cost)开销 ——达到对命令/值的一致性—— 仅为运行这个一致性算法的阶段2的开销(cost of executing only phase 2 of the consensus algorithm.)。能够被展示出来,为了达成一致,在允许失效的情况下(in the presence of faults),在所有的同类(一致性)算法中, paxos一致性算法的阶段2具有最小可能的开销[2]。因此paxos算法在本质上是最佳的(optimal)。[ 译者注: "仅运行阶段2"有点 multi paxos的味道, wiki上的multi paxos时序图 如下: ] [ 事实上后来演进的算法是能够做到 leader确保仅一台 , 即当选leader要超过半数同意, 且二阶段仅对leader答复且要超过半数, zab/raft 均是如此 ]     

无leader和多leader情况安全性说明 [译者新增二标题]

对系统正常(normal)操作的讨论假设一直存在单个(single)leader,除去(except)在当前leader失效和选举新leader之间的一小段时间。在异常环境中,leader选择可能失败。如果没有服务器被选为leader,那么没有新命令会被提议。如果多个服务器都认为自己是leader,在同一个算法实例中,它们将都能提出提议,这可能会导致所有的提议都不能被选择。然而,安全属性是保持的(preserved) —— 两个不同的服务器永远不会在第i个状态机命令的值上有分歧(disagree)。选择单一的leader只是为了确保流程(progress)(不活锁)。

如果服务器的集合会变动 [ 译者注: 前面文章中指定了不会变fixed ],那么必须有某种方法能够确定哪些服务器执行的是算法的哪个实例。最简单的做法就是让状态机自己做到。当前的服务器集合可以作为状态的一部分,并能被普通的状态机命令修改。通过(执行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的实现】

]

参考文献

[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.

附录

译者注释,证明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,由此得证结论

注释结束]

翻译过程参考资料

  • Paxos Made Simple
  • Wikipedia: Paxos (Computer Science)
  • StackExchange Discussion: Paxos made simple, invariant P2c
  • StackExchange Discussion: The proof of P2b in Paxos made simple
  • Paxos Made Simple 译文
  • 维基百科: 状态机复制
  • Safety & Liveness Properties
  • 彻底厘清真实世界中的分布式系统
  • 百度百科:第二归纳法

辅助翻译工具

from 《Paxos Made Simple》中文翻译:Paxos 如此简单  这里面有对应到原文上.

  • 有道词典

  1. 让人摸不着头脑:原文中的词是“Greek”,我个人猜想这里其实是一语双关,一个意思是指 Leslie Lamport 第一次阐述 Paxos 算法的论文《The Part-Time Parliament》里用了古希腊的故事情节来阐述算法思路,另一个意思表达令人摸不着头脑,可参考有道词典双语例句:
    Reporter: The new version will promote "The Painted" as "Eastern magic of the new", is not it a bit too exaggerated and Greek?Positioning yourself how this movie?
    记者:宣传方将新版《画皮》定位为“东方新魔幻”,是不是有点儿太夸张并且令人摸不着头脑?你自己怎么定位这部电影?。
     ↩
  2. synod 算法:论文作者在《The Part-Time Parliament》中对其算法的命名为 synod。 ↩
  3. 来自维基百科的“状态机复制”词条:多个相同状态机的拷贝,从同样的“初始”状态开始,经历了相同的输入序列后,会达到同样的状态,并且输出同样的结果。 ↩
  4. 原文中为单词values,翻译过程中结合上下文理解,认为加上“可能不同的”会更贴合情境。 ↩
  5. 原文内容为“A process never learns that a value has been chosen unless it actually has been.” ↩
  6. 关于安全性属性以及活性属性,可查阅“本文参考资料”一节的“Safety & Liveness Properties” ↩
  7. 原文单词“corrupted”,直译应为“损坏”,但是这里结合个人理解,译作“篡改”更贴切,意为不会发生拜占庭式的问题 ↩
  8. 由于所谓的大多数等于 N/2+1,所以如果有一个接受者故障,可能导致两边提议都只能得到 N/2 票,都无法行成大多数。 ↩
  9. 一种常见且可行的方案是使用时间戳+机器ID的形式,但是实际上论文中并没有对提案编号的生成做具体的规定,只要保证编号递增且唯一即可,所以实际的实现中可以有多种多样的实现方式 ↩
  10. 论文作者采用了数学上的第二归纳法,亦称“强归纳法” ↩
  11. 结合后面的推理结论,这里是一个闭区间的标记法,即i..j对应数学记法 [i, j]。 ↩
  12. 至少接受了 m 号提案,所以这个结论是成立的 ↩
  13. 记得一个“提案”始终意味着:一个编号加上一个提案的值。 ↩
  14. 回想基本的 Paxos 的两个阶段中的阶段一,只要当前实例中,还没有任何提案被接受者接受过,则提议者可以提出任意值。这种情况下,意味着原来旧的 Leader 还没有来得及开始实例 136 和 137 的阶段二。 ↩

Paxos Made Simple【中文翻译注解】相关推荐

  1. Paxos Made Simple 中文翻译

    目录 1. 引言 2. 共识算法 2.1 问题 2.2 选择一个 value 2.3 获知选定的 value 2.4 可进行性 2.5 实现 3. 实现状态机 Paxos Made Simple 基础 ...

  2. Paxos Made Simple

    Paxos一致性算法--分布式系统中的经典算法,论文本身也有一段有趣的故事.一致性问题是分布式系统的根本问题之一,在论文中,作者一步步的加强最初一致性问题(2.1节提出的问题)的约束条件,最终导出了一 ...

  3. halcon11用于C++的HTuple.h头文件,纯手添中文翻译!

    halcon11用于C++的HTuple.h头文件,纯手添中文翻译!乐于分享,请勿在非同意下转载! /************************************************* ...

  4. Z-Stack Home Developer's Guide—3. The Home Automation Profile and the Sample Applications中文翻译

    下面是Z-Stack Home 1.2.0开发资料中的Z-Stack Home Developer's Guide-3. The Home Automation Profile and the Sam ...

  5. eZ Publish 的 Site.INI文件的中文翻译

    Site.INI文件的中文翻译 #?ini charset="iso-8859-1"? # eZ publish 配置文件 # 注意:并不建议直接修改这个文件,最好是写一个这个文件 ...

  6. MapReduce:Simplified Data Processing on Large Clusters(中文翻译2)

    [注:本人菜鸟一枚,喜欢Hadoop方向的大数据处理,现在正在研读Google影响世界的三篇论文,遂一边阅读一边翻译,错误在所难免,希望大家给予批评,我会增加学习的动力] 1 Introduction ...

  7. Why Memory Barriers?中文翻译(上)

    转载自:Why Memory Barriers?中文翻译(上) 本文是对perfbook的附录C Why Memory Barrier的翻译,希望通过对大师原文的翻译可以弥补之前译者发布的关于memo ...

  8. vue中文翻译拼音组件_Vue组件可简化文本的翻译方式:通过内联翻译

    vue中文翻译拼音组件 @ alidrus / vue-simple-inline-translation (@alidrus/vue-simple-inline-translation) A Vue ...

  9. [非卷积5D中文翻译及学习笔记] 神经辐射场 NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis

    不使用3D建模,使用静态图片进行训练,用(非卷积)深度网络表示场景的5D连续体表示,再通过ray marching进行渲染. 本中文翻译使用"机器学习+人工校准/注解"的方式完成. ...

最新文章

  1. np.reshape 中的 -1 参数
  2. 设置共享,实现Linux和Windows之间的共享
  3. Ubuntu下gedit的相关问题
  4. 你以为AlphaGo只是下围棋厉害?不,它还能用来优化金融交易策略参数
  5. 获取要素集中字段的唯一值
  6. 织梦后台如何生成站点地图sitemap.xml
  7. 台阶问题(洛谷-P1192)
  8. SQL Server日期格式和SQL Server转换举例说明
  9. Discuz在Firefox下无法切换至编辑器状态解决(Z)
  10. 大数据分析机器学习(一)之线性模型-年龄和心率关系
  11. 【Elasticsearch】 es ES节点memory lock重要性与实现方式
  12. [原创]纯CSS3打造的3D翻页翻转特效
  13. typora绑定github博客_博客生产线:WordPress(平台)+Typora(编辑器)+GitHub(图床)
  14. 明日决战!TI8冠军OG与OpenAI人机大战现场探营
  15. 2008年全国计算机等级考试须知及参考资料
  16. 停掉一台服务器,Nginx响应慢(转载)
  17. 2019最新 Java商城秒杀系统的设计与实战视频教程(SpringBoot版)_2-1微服务项目的搭建-SpringBoot搭建多模块项目一...
  18. 动态规划实战8 leetcode-53. Maximum Subarray
  19. 分析国内App推广渠道和方法
  20. 最小二乘法求线性回归方程

热门文章

  1. Unity3D UGUI 实现翻书特效
  2. 华为FusionServer Pro V6 智能服务器
  3. 正在配置更新 请不要关闭您的计算机,Win7启动屏幕显示“正在配置Windows Update,请不要关闭”如何解决...
  4. 【这可能不只是一篇面经】- 有话想说的四个月 【转】
  5. 电脑重启后Mysql丢失原先的数据库
  6. 2017年“嘉杰信息杯” 中国大学生程序设计竞赛全国邀请赛:I— Strange Optimization
  7. 【代码重构(Refectoring)系列教程 基本概念二】何时应该重构?如何去重构?
  8. 江湖问心不问路--叹韩非子
  9. 计算机科学与技术 色盲限制,2021男生色盲学什么专业比较好 受限专业有哪些
  10. php不用框架怎么写,教你在不使用框架的情况下也能写出现代化 PHP 代码