《Paxos Made Simple》中文翻译:Paxos 如此简单

October 2020 · 4 minute read

写在前面

个人在学习理解 Paxos 算法的过程中,花了比较多的时间,从最开始直接查看中文博客资料,感觉都是看完不知所以然或者有很多疑问,于是决定死磕《Paxos Made Simple》论文原文。但是由于有些英文的意思我自己理解起来还是有点困惑,于是过程中遇到无法理解的内容,一方面是会翻阅前辈们已经写过的论文的翻译作为参考,二是在搜索引擎里就一些难以理解的点搜索中英文的讨论,以此解决自己心中的困惑。在磕磕碰碰中完成论文的阅读之后,仍有一些不尽透彻之处,加上个人认为此论文已有的翻译质量参差不齐,所以斗胆想通过翻译以及必要译注再次加深自己的理解,另外可能的话,也希望本次翻译能够帮助到未来可能会遇到和我一样困惑的人。

部分关键术语表

论文中有一些关键术语,我已经力求用词准确,并在论文中尽力保持术语翻译的一致性,目的是尽量充分传达论文本身用词的精准,建议读者可先仔细阅读此表。

原文术语翻译中使用术语译者注
value(s)值可能比较抽象,觉得太抽象的读者建议理解为提案的“内容”亦可
learn获知有些文章译作“了解”或者“学习”,但是这里反复斟酌,还是觉得“获知”更贴切,目的性更强烈
propose提议
chosen选定一个被选定的值,意味着一个被“一致”确认下来的值
agent代理依旧觉得翻译成“代理”过于字面化
proposer(s)提议者
acceptor(s)接受者
learner(s)学习者
fail / failure失效/故障意味着系统已经完全不能工作
proposal提案
accept接受
number编号
distinguished特定的文中用于形容某个经过选举而被选中的角色

翻译全文

Paxos 如此简单

2001年11月1日

摘要

当用浅显易懂的英语来表达的话,Paxos 是非常简单的。

1 导引

Paxos 算法——一个用于实现一个容忍错误的分布式系统的算法,让很多人觉得难以理解,这可能是因为对于很多读者们而言,原来的表述太过于让人摸不着头脑1了。事实上,它是最简单浅显的分布式算法。它的核心是一个一致性算法——“synod”算法2。在下一节中,将会看到这个一致性算法不可避免地遵循一些我们希望它能够满足的特性。最后一节阐述了完整的 Paxos 算法,这个算法是通过将一致性(的实现)直接应用到用于构建分布式系统的(多副本)状态机3这种方法中得到的——这种所谓的方法应该是众所周知的,因为它是分布式系统理论中最常被引用的论文的主题。

2 一致性算法

2.1 问题描述

假设有一个由多个进程组成的集合,集合里的每个进程都可以提议(可能不同的)值4。一致性算法保证在被提议的这些值中只有一个值能够被选定。一旦一个值被选定,则所有进程都需要能够获知(learn)这个被选定的值。一致性的安全性要求做到:

我们不会尝试去明确精准的活性要求6。无论如何,(算法的)目标是要保证被提议的值中有某个值能够被选定,并且一旦一个值被选定了,进程最终能够获知这个被选定的值。

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

设想代理之间可以通过发送消息的方式相互通信。我们使用传统的异步(模型),而不是拜占庭问题模型,也就是说:

2.2 值的选定

选定一个值的最简单的方式就是只有一个接受者的代理:一个提议者将一个提案发送给这个接受者,而后者直接选定它收到的第一个提议的值即可。这种方案虽然简单,却是无法叫人满意的,因为这个(唯一的)接受者一旦失效,将导致后续的操作无法继续。

所以,让我们来尝试选定值的另一种方法吧。不再是单一的接受者,我们现在尝试使用多个接受者代理的方式。一个提议者将一个提议的值发送给一群接受者。一个接受者可能*接受(accept)*这个被提议的值。一旦一个足够大数量的接受者的集合都接受了一个值,那么这个值就可以算是被选定了。多大的数量才算足够大?为了确保有且只有一个值被选定,我们可以让一个所谓足够大的集合等同于这些代理中的“大多数”组成的集合。因为任意两个“大多数”的集合必然拥有至少一个共同的接受者,并且假如一个接受者最多只能接受一个值,这个方法就是行得通的。(在很多的论文中都有对于“大多数”的浅显的概括)

在不考虑(系统)故障或者消息丢失的情况下,我们期望在哪怕只有一个提议者提出值的时候也能选定一个值。这引出了条件:

P1. 接受者必须接受它收到的第一个提案。

但是这个条件引入了另一个问题。在几乎同一时间,多个不同的提议者可能提议多个不同的值,并且发生了一个特殊情况:每个接受者都接受了其中一个值,但是没有任何一个值被接受者中的“大多数”所接受。甚至只有两个提议的值,一旦它们各自被差不多一半的接受者所接受,此时即使只有一个接受者故障都可能使得无法确定该选定哪个提案8

结合P1以及“只有被大多数接受者所接受的值才能被选中”的要求,可以发现隐含条件:必须允许接受者接受不止一个提案。我们使用对每个提案进行(自然)编号的方式来跟踪接受者可以接受的不同的提案,这样的话,每个提案都包含了一个提案编号以及对应的值。为了防止混淆,我们要求不同的提案必须要有不同的编号。至于怎么实现不同的编号则取决于实现的方案9,这里我们只要做假设就好了。当一个带有某个值的提案被大多数的接受者接受了之后,这个值就算是被选定了。在这种场景下,我们可以说这个提案(以及它的值)已经被选定了。

我们可以允许多个提案被选定,但是必须保证所有被选定的提案拥有一样的值。结合提案编号归纳推理,只要保证以下条件就够了:

P2. 如果一个拥有值 v 的提案被选定,则每一个(比这个提案)更高编号且被选定的提案也都拥有值 v

由于(提案)编号是完全有序的,条件 P2 保证了至关重要的安全性属性:只有一个值被选定。

为了被选定,一个提案必须被至少一个接受者所接受。于是,我们通过满足以下条件来满足 P2:

P2a. 如果一个拥有值 v 的提案被选定,则每一个(比这个提案)更高编号且被任意一个接受者接受的提案也都拥有值 v

我们仍需坚持 P1 以保证某个提案能被选定。(并且)因为消息通信是异步的,一个提案可能会被某个从来没有收到过任何提案的特殊接受者 c 所接受。设想一个新的提议者“醒来”并且提议了一个更高编号且值不同的提案的场景。P1要求 c 不得不接受这个提案,但这又会打破 P2a 的条件。为了同时满足 P1 和 P2a,需要对 P2a 做进一步加强:

P2b. 如果一个拥有值 v 的提案被选定,则每一个(比这个提案)更高编号且被任意一个提议者提议的提案也都拥有值 v

由于只有被提议者提议的提案,才可以被接受者接受,所以 P2b 隐含了 P2a,也进一步隐含了 P2。

为了发现如何满足 P2b,我们考虑如何证明它成立。我们先假设某个编号为m,且值为 v 的提案已经被选定,然后证明任何编号为 nn > m)的提案也都拥有值 v。我们可以通过对 n 采用数学归纳法10以使证明过程更轻松,于是在以下额外的假设下可证明编号为 n 的提案拥有值 v

归纳假设:每一个编号在 m..(n-1) 之间的提案都拥有值 v,这里的 i..j 的记法代表从 ij 的一组编号。11

集合 C 里的每个接受者都接受了编号在 m..(n-1) 之间的一个提案12,并且被任何一个接受者所接受的每一个编号在 m..(n-1) 之间的提案都拥有值 v。

由于任意一个由大多数接受者组成的集合 S 都必然包含集合 C 的至少一个元素,我们可以通过维护以下不变性以保证编号为 n 的提案拥有值 v

P2c. 对于任意的 v 和 n,如果一个编号为 n 且拥有值 v 的提案被提议,则存在一个由大多数接受者组成的集合 S 满足这里其中一个条件:(a)集合 S 里没有接受者接受了任何一个编号小于 n 的提案;或者是:(b)v 是集合 S 中的接受者已经接受过的所有编号小于 n 的提案中编号最高的提案的值。

因此我们可以通过维护 P2c 的不变性来满足 P2b 的条件。

为了维护 P2c 的不变性,想要提议编号为 n 的提案的提议者必须获知编号小于 n 的最大编号的提案,如果存在这样的提案的话,那它肯定是已经或者即将被大多数接受者所接受的提案。获知已经被接受的提案是足够简单的,但是预测未来哪些(提案会被)接受则是困难的。与其尝试去预测未来,不如让提议者通过获取一个**“将不会存在任何一个这样的接受”**的承诺来控制这个过程。换句话说,提议者请求接受者们不再接受任何编号比 *n* 小的提案。这就引出了以下用于提议过程的算法:

  1. 一个提议者选择一个新的提案编号 n,然后给由某些接受者组成的集合中的每一个成员发送一个请求,要求它响应以下信息: a. 一个承诺:不再接受任何一个编号比 *n * 小的提案,并且 b. 如果它已经有接受过提案的话,则还要返回它已经接受过的编号比 n 小的最大编号的提案13 我把这样一个请求称之为对编号 nprepare 请求。
  2. 如果提议者从大多数的接受者成功收到期待的响应,则它可以接着提议一个编号为 n 且值为 v 的提案,这里 v 就是它从1b 中收到的响应里最大编号的提案的值,如果所有响应都表明没有接受过任何提案,则提议者可以自由选择一个值。 提议者通过向一组接受者发送一个请求来提议提案。(这里的这组接受者并不需要和响应 request 请求的接受者一致)。让我们把这个请求称之为 accept 请求。

前面这些内容描述了提议者的算法,但是对于接受者而言又该是怎样子的呢?它可以接收来自提议者的两种请求:prepare 请求和 accept 请求。接受者可以忽略任何请求而不影响安全性。所以,我们需要讨论只在哪些情况下它可以响应请求。它总会响应 prepare 请求;它也可以响应 accept 请求,接受提案,只要它(事先)没有承诺不这样做。换句话说:

P1a. 接受者可以接受编号为 n 的提案,只要它没有响应过编号大于 n 的 prepare 请求

可见 P1a 包含了 P1。

我们现在已经得到了一个足以满足安全性属性的用于选定值的完整算法——在假设提案号唯一的基础上。最终的算法还需要通过额外的一点优化来得到。

设想一个接受者收到了一个编号为 nprepare 请求,但是它已经响应过一个编号比 n 大的 prepare 请求,因此也就承诺了不再接受任何编号为 n 的新的提案。于是接受者没有理由要去响应这个新的 prepare 请求,因为它并不会考虑接受编号为 n 的提案,也就是提议者想要提议的提案。所以我们让接受者直接忽略这样一个 prepare 请求。我们也让接受者直接忽略它已经接受的提案的 prepare 请求。

加上这个优化,接受者只需要记录它已经接受过的最高编号的提案以及它已经响应过的最高编号的 prepare 请求的编号即可。因为无论失败与否,P2c 都必须保持不变,所以接受者必须能够记录这些信息,哪怕它可能崩溃,以及重启。注意提议者总是可以放弃某个提案并且装作什么都没有发生过——只要提议者不会尝试用相同的编号提议另一个提案。

将提议者和接受者的行为都放在一起,我们可以看到这个算法的操作可以分为以下两个阶段:

阶段 1:
(a)提议者选择一个提案编号 n,向“大多数”接受者发送一个带有编号 n 的 prepare 请求;
(b)如果接受者收到一个编号为 n 的 prepare 请求,且 n 比它已经响应过的任何一个 prepare 请求的编号都大,则它会向这个请求回复响应,内容包括:一个不再接受任何编号小于 n 的提案的承诺,以及它已经接受过的最大编号的提案(假如有的话)。

阶段 2:
(a)如果提议者从“大多数”接受者收到了对它前面发出的 prepare 请求的响应,它就会接着给那每一个接受者发送一个针对编号为 n 且值为 v 的提案的 accept 请求,而 v 就是它所收到的响应中最大编号的提案的值,或者是它在所有响应都表明没有接受过任何提案的前提下自由选择的值 v;
(b)如果接受者收到了一个针对编号为 n 的提案的 accept 请求,它就会接受这个请求,除非它之前已经响应过编号大于 n 的 request 请求。

提议者可以提议多个提案,只要它在每一个提案中都遵循上面的算法。它也可以在协议中间的任何时候丢弃提案。(正确性还会被保持,哪怕是对废弃提案的请求或者响应可能在提案被丢弃很久之后才到达目的地)。在某些提议者已经开始尝试提议更高编号的提案的情况下,(尽早)放弃(当前较低编号的)提案或许是一个好的主意。所以,如果接受者由于它自身已经收到了更高编号的 prepare 请求而选择忽略(当前的)prepare 或者 accept 请求,那它应该通知提议者,提议者应该在收到通知后放弃提案。总体而言,这是一个不会影响正确性的性能优化。

2.3 获知选定的值

为了获知值已被选定,学习者必须找出某个已经被大多数接受者接受的提案。最显而易见的算法就是让每一个接受者一旦接受了提案,就响应给所有学习者,并给它们发送接受了的提案信息。这种方法允许学习者们尽可能快地找出被选定的值,但这种方法也要求每个接受者要响应每个学习者——响应的数量等于接受者数量和学习者数量的乘积。

没有拜占庭式错误的这样一个假设使得一个学习者可以很容易地通过其他的学习者来获知某个值已被接受的事实。我们可以让接受者将它们的接受事件响应给某个特定的学习者,这个特定的学习者要负责在每次一个值被选定之后通知其他的多个学习者。这种方法要求所有的学习者花费额外一轮的时间用于获知被选定的值,也降低了可靠性,因为那个特定的学习者可能会故障。但是这个方法要求的响应数量只等于接受者的数量和学习者的数量之和。

更一般的,接受者可以将它们的接受事件响应给由多个特定的学习者组成的某个集合,集合中的每个学习者都会在每次一个值被选定之后通知所有的学习者。使用这样一个较大的特定的学习者组成的集合可以在更大的通信复杂度上提供更大的可靠性。

由于消息丢失,值可能在学习者无法发现的情况下被选定。学习者可以询问接受者:现在已经接受了什么提案?但是接受者的失效可能导致不可能知道是否有一个大多数的(接受者)已经接受了某个特定的提案。在那种场景下,学习者只能在一个新的提案被选定的情况下才能找出哪个值被选定了。如果学习者需要知道一个值是否已经被选定,它可以让提议者使用上面描述的算法提议一个提案即可。

2.4 可进行性

构建这样一个场景是容易的:两个提议者相继提议一系列递增编号的提案,但是没有哪一个提案能被选定。提议者 p 完成了编号 n1 的提案的阶段1,接着另一个提议者 q 也完成了编号 n2n2 > n1)的提案的阶段1.由于接受者已经承诺不会再接受任何编号小于 n2 的新提案,所以提议者 p 在阶段2为提案 n1 发送的 accept 请求会被忽略。所以,提议者 p 又接着开始并且完成了一个新的提案 n3n3 > n2)的阶段1,导致提案 q 的阶段2的 accept 请求也被忽略了,以此类推……

为了保证(过程)可进行,一个特定的提议者必须被选为唯一一个提议提案的。如果这个特定的提议者可以成功地和大多数接受者通信,并且它使用了编号比任何已经使用的编号大的提案,那么它将会成功完成提议,也就是说,提案会被接受。通过在发现某个请求已经使用了更高的提案编号的情况下主动放弃提案然后重试(阶段1),这个特定的提议者终将能够选到一个足够高的提案编号。

如果系统有足够多的组件(提议者、接受者以及通信网络)正常工作,那么就可以通过选举一个单一的特定的提议者来实现活性。Fischer, Lynch 和 Patterson 的著名(实验)结果指出:选举一个提议者的可靠算法必须使用随机性或者实时性——举例来说,使用超时机制。无论如何,不管选举成功或者失败,安全性都是可以保证的。

2.5 实现

Paxos 算法假设了一个多进程组成的网络。在它的一致性算法里,每个进程同时扮演了提议者、接受者和学习者。这个算法也会选定一个 leader,由它同时扮演特定的提议者以及特定的学习者。Paxos 一致性算法正是上面描述的算法,其中请求和响应都作为普通消息发送。(响应的消息都会用对应的提案的编号做标记,以防混淆。)需要持久化存储器在故障时发挥作用,用于维护接受者必须记住的信息。接受者需要在真正发出响应之前在持久化存储上记录它计划的响应。

剩下的就是描述一种能够保证不同的提案不会使用相同的编号提议的机制。只要不同的提议者从不相交的编号集合中选择编号,这两个不同的提议者提议的提案就一定不会拥有相同的编号。每个提议者在稳定的存储上记录各自已经尝试提议的最高编号的提案,然后使用一个比它已经用过的编号更高的提案编号再次开始阶段1的过程。

3 实现一个状态机

实现分布式系统的一种简单方式是作为向中央服务器发出命令的客户端的集合。可以将服务器描述为一个按照时序执行客户端命令的确定状态机。这个状态机拥有一个当前的状态,它通过接受一个命令作为输入来执行一个步骤,然后产生一个相应的输出以及一个新的状态。举个例子:一个分布式的银行系统的客户端可能是出纳员,而状态机的状态则由所有用户的账号余额组成。一个取款操作可以通过运行一个状态机命令来完成:这个命令当且仅当余额大于取款数量的时候才可以扣减账户余额,并生成新旧余额作为输出。

使用单个中央服务器的实现方案会随着服务器的崩溃而失效。于是,我们想到了可以使用一组服务器,每个服务器彼此独立地实现同样的状态机。由于状态机是确定的,所以如果所有服务器都执行了相同的一系列命令,那么所有服务器都将会产生同样的一系列状态以及输出。一个发出命令的客户端则可以任意采用一台服务器生成的输出。

为了保证所有服务器运行相同的一系列状态机命令,我们(需要)实现 Paxos 一致性算法的一系列独立的实例,第 i 个选定的值就是序列中的第 i 个状态机命令。每一个服务器都在每一个实例中扮演这个算法的所有角色(提议者、接受者和学习者)。就现在而言,我假设服务器的集合是固定的,所以这个一致性算法的所有实例使用相同的一群代理。

在正常操作中,一个单独的服务器被选举为了 leader,由它在这个一致性算法的所有实例中扮演特定的提议者(只有它会尝试提议提案)。(多个)客户端发送命令到 leader,leader 决定每个命令的时序。假如 leader 决定某条客户端命令应该是第 135 个命令,那么它就会尝试通过这个一致性算法的第135个实例来提议选定一个提案,命令本身就是这个提案的值。这个过程通常会顺利完成。但它也可能因为故障而失败,或者因为有另一个服务器认为它自己才是 leader 并且它认为第 135 个命令应该另有他值。但是这个一致性算法确保第 135 位上最多只有一个命令能够被选定。

在 Paxos 一致性算法里,这个方法的效率的关键在于,被提议的值要到阶段2才会被选定。回想一下,在完成提议者的算法的阶段1之后,要么要提议的值已经确定下来,要么提议者可以自由提议任何值。

我现在将要描述 Paxos 状态机的实现是如何在正常操作下发挥作用的。稍后的话,我也将会讨论我们可能会遇到什么问题。我考虑的是在前一个 leader 刚发生故障而新的 leader 已经被选举出来的时候,会有什么事情发生。(系统启动是一个特殊场景,这个时候还没有任何命令被提议)

这个新的 leader 也是这个一致性算法的所有实例中的学习者,它应该知道大多数已经被选定的命令。假设它知道 1-134、138 以及 139 号命令,也就是一致性算法的 1-134、138 以及 139 号实例的值。(我们稍后将会看到命令序列中的这样一个空缺是如何产生的。)然后它执行实例135-137以及所有大于139的实例的阶段1,假设这些执行的结果只确定了实例 135 和 140 中提议的值,但是其他实例中没有提议值的约束14。leader 执行实例 135 和 140 的阶段2,并因此可以选定 135 和 140 号命令。

leader 自身就像其他向 leader 学习 leader 所知道的所有命令的别的服务器一样,现在可以运行命令 1-135。因为136号和137号命令还没有选定,所以它还不能运行 138-140 号命令,尽管它知道 138-140 号命令。于是,我们让它通过提议将一个特殊的不会导致状态机状态切换的“no-op”命令作为第136号和137号命令(它可以通过执行一致性算法的 136 号和 137 号实例的阶段 2 来完成),以此快速填补空缺。一旦这些 no-op 命令被选定,那 138-140 号命令就可以被执行了。

现在从 1 到 140 的命令都被选定了。 leader 完成了一致性算法中大于 140 的所有实例的阶段 1,它可以在这些(完成阶段1的)实例的阶段2中自由地提议任意的值。它给某个客户端请求的下一个命令分配了 141 号命令,把它作为这个一致性算法的 141 号实例的阶段2提议的值。它接着将它收到的下一个客户端命令提议为第 142 号命令,以此类推。

leader 可以在它获知它提议的 141 号命令已被选定之前提议 142 号命令。它在提议第 141 号命令中发送的所有消息有可能丢失,而第 142 号命令会在其他服务器获知到 leader 提议的第 141 号命令之前被选定。当 leader 在实例 141 中没有收到对它的阶段2的预期响应时,它将会重发这些消息。如果一切顺利,它提议的命令会被选定。无论如何,它还是有可能在前面有失败,在选定的命令的序列上留下一段空缺。一般来说,假设一个 leader 可以提前获得 α 个命令——也就意味着,它可以在 1 到 i 号命令被选定之后提议第 i + 1 到 i + α 号命令。一个多达 α - 1 个命令的空缺可能随之形成。

一个新的被选定的 leader 执行一致性算法中的无限多的实例的阶段1——如果是在上面的场景中,就是实例 135-137,以及所有大于139的实例。让所有实例使用一样的提案编号,它可以通过向其他的服务器发送一个合理的短消息来实现这一点。在阶段1中,接受者当且仅当它已经收到了某个提议者的阶段2的消息的时候,它才会响应不止1个简单的OK。(在这个场景里,这是仅针对实例 135 和 140 的例子。)所以,一个(扮演接受者的)服务器可以用一个单一且合理短的消息回应所有的实例。因此,执行阶段1的无穷多个实例不会带来任何问题。

由于 leader 的故障以及新 leader 的选举理应很少发生,因此执行状态机命令——对命令/值达成一致的过程的有效成本,仅为运行这个一致性算法的阶段2的成本。可以看出,Paxos 一致性算法的第2阶段在存在故障的情况下,其达成协议的可能代价是所有算法中最小的。于是,Paxos 算法本质上是最优的。

对于系统正常操作的讨论中假设了总是只有一个单独的 Leader,排除了现任 Leader 故障和新任 Leader 选举之间的一小段时间。在异常的情况下,Leader 选举可能失败。如果没有服务器担任 Leader,也就没有新的认领会被提议。如果多个服务器认为它们自己都是 Leader,则它们都可以在这个一致性算法的同一个实例上提议值,这可能导致没有值能够被选定。尽管如此,安全性还是保证的——两个不同的服务器将不会对被选定的第 i 个状态机命令持有不同意见。单个 Leader 的选举只有在确保(整个过程)可进行的时候才需要。

如果服务器的集合可以变化,那必然存在某些方式用于决定哪些服务器实现这个一致性算法的哪些实例。最简单的方式就是通过状态机自己。当前的服务器集合可以成为状态的一部分,并且可以通过普通的状态机命令修改。通过让运行第 i 个状态机命令后所指明的服务器的集合来运行这个一致性算法的第 i + α 号实例,我们可以允许 Leader 提前获得 α 个命令。这允许了一个任意复杂的支持重配置的算法的简单实现。

原论文参考文献

[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 Com- puter Systems, 16(2):133–169, May 1998.

翻译过程参考资料

辅助翻译工具


  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]。 由于编号为 m 的提案已经被选定,那就必然存在一个由“大多数”接受者组成的集合 C,且集合里的每一个接受者都接受了这个提案。结合这个(推理)以及前面的归纳假设,m 被选定的假设则意味着: ↩︎

  12. 至少接受了 m 号提案,所以这个结论是成立的 ↩︎

  13. 记得一个“提案”始终意味着:一个编号加上一个提案的值。 ↩︎

  14. 回想基本的 Paxos 的两个阶段中的阶段一,只要当前实例中,还没有任何提案被接受者接受过,则提议者可以提出任意值。这种情况下,意味着原来旧的 Leader 还没有来得及开始实例 136 和 137 的阶段二。 ↩︎