Paxos Made Simple个人翻译

原文链接:https://lamport.azurewebsites.net/pubs/paxos-simple.pdf

译者前言

翻译是辅助观看论文的工具。作者写翻译的原因是为了保证自己在阅读论文时,能够逐字逐句阅读全篇论文,并且在再次阅读论文时,自己翻译的部分能够更好的回忆起相关的思维情况。

本篇翻译是在参考其他翻译的同时做的翻译,感谢其他博主。

译者水平有限,还有本质是个人笔记,无法保证完整的翻译质量。如有问题,希望谅解。如可指出,也非常感谢。

摘要

用通俗易懂的英语去讲述paxos算法,是真的非常简单。

1 介绍(introduction)

可能因为之前官方对paxos的描述对大多数读者来说,是一件困难的事情,作为一个带容错的分布式系统算法,paxos算法被认为是难以理解的。但实际上,在分布式算法中这应该是最简单,最显而易见的。它的本质其实是一种共识算法——the “synod” algorithm of[5]。下一节讲述的是为了满足这个算法需要达成的相关特性。最后一节讲述的则是在通过直接应用协商一致的状态虚拟机来构建分布式系统应用paxos协议。这应该是常见的,也是分布式系统理论中被引用最多的领域。

2 共识算法(The Consensus Algorithm)

2.1 问题提出(The Problem)

假设有一系列可以提议(propose)value的进程。一个共识算法需要保证最终在被提议value之中只有一个被选择(chosen)。当然,如果没有value被提议(proposed),那自然没有value会被选择(chosen);而如果有一个value被提议(chosen),那么对这一批进程都需要获取(learn)到这个value(chosen value)。为了达成这种共识有些必须的要求:

  • 只有一个value能被选定,在被提议(proposed)的value中
  • 只能是单个(single)value被选定 [未充分理解]
  • 一个进程能学习到一个value当且仅当这个值被选定

我们不是尝试去指定一些精确的要求。但是,这个问题的目标是:在一批被提议的value中,最终有一个value被选定(chosen),以及一个value以但被选定,那么其他进程最终能获取(learn)到这个value。

我们三种agent来代表共识算法中的三类角色:proposers, acceptors和learners。在具体实践中,一个进程可以会扮演者不止一种角色,但是目前我们并不关心agent到进程中的映射的问题。

假设agents之间能够通过发送信息来互相通信。我们使用传统的异步、非拜占庭模型,以及以下条件:

  • Agents速度任意,可能发生故障,可能重启。因为所有的agents在一个value被选定(chosen)后重启,所以除非agent在发生故障或者重启时能记住一些信息,否则一般的方法是不可行的。
  • 发送的message可以是任意长度,可能重复发送,可能丢失,但不会损坏。

2.2 选定一个value(Choosing a Value)

最简单的是在只有一个acceptor agent的场景。一个proposer发送一条提议给acceptor,后者从中接受最早收到的value。然而虽然简单,这种方法不能满足我们的要求,因为如果acceptor发生故障,则会导致任何接下来的操作都无法进行。

因此我们来尝试以下其他方法来选择(choosing)一个value。这时不再是一个acceptor,而是多个acceptor的集合。proposer发送一个被提议的(proposed)value给一组acceptors。acceptor可能会accept一个被提议的(proposed)value。但是value会被选定(chosen)当且仅当有一个足够多数量的acceptor去接受它。多大才能满足这里足够的要求?为了保证只有一个value会被选中(chosen),我们假设一个足够打的agents集合包含任意多个agents群体。而能达成要求的情况是对于任意的两个群体,至少有一个公共的acceptor*(大概意思是至少有一个accept了一个被提议的value?)*。

在没有故障和message丢失的情况下,我们要是一个value被选中(chosen),当且仅当每个value只对应一个proposer。这就需要满足以下的要求:

P1 acceptor需要accept第一条接受到的提议(proposal)

但是这个要求会引申出一个问题。同一时刻可能有多个不同的proposer提议出多个value,虽然每个acceptor都accept了一个value,但没有其中一个value被大多数acceptor所接受。甚至在只有两个被提议的value的情况下,假设每个都被一半的acceptor所accept,那么任意单个acceptor的故障都将让我们无法获取它选择了哪个value。

P1以及只有一个被大多数acceptors选定的value才能被选定(chosen)的要求,导致了我们的acceptor必须要能接受不止一个的proposal。我们通过给每个proposal赋予一个编号来追踪不同的proposal,一个proposal由一个proposal number和一个value组成。为了防止出现歧义,我们要求不同的proposal要有不同的number。如何实现需要根据实际场景,这里我们只做一种假设。一个value会被选定(chosen)的场景是在包含这个value的请求accepted by大多数的acceptors。在这种情况下,我们说这个提议(包括这个value)被选定(chosen)了。

我们允许多个提议能够同时被选定,但我们必须保证所有被选定(chosen)的提议都拥有相同的value。通过对提议数字的归纳,足以保证:

P2 如果一个value v v v的提议被选定,那么所有更高编号的被选定的(chosen)提议的也拥有value v v v

在数字有序的情况下,P2能够保证一个关键性的安全特性是只有一个value被选定(chosen)。

为了使value最终能被选定(chosen),提议要accpeted by至少一个acceptor。因此,我们可以通过满足以下条件来满足P2

P2 a ^a a 如果一个value为v的提议被选定(chosen),那么acceptor接受到的所有任意编号更高的提议都拥有value v v v

我们仍然满足P1来确保提议能被选定(chosen)。因为交互是异步的,这会导致一些特定的acceptor c c c从来没有接受到任何提议。假设此时一个新的proposer恢复并发出一个带有更高编号的带有不同value的提议。P1的条件使得 c c c会接受(accept)这个提议,而这会违背P2 a ^a a条件。为了同时维护P1和P2 a ^a a,将P2 a ^a a加强到如下:

P2 b ^b b 如果一个value v v v的提议被选定(chosen),那么之后每个proposer发出的更高编号的提议都拥有value v v v

因为在被acceptor接受之前一个提议必须通过一个proposer来发布,P2 b ^b b可以证明P2 a ^a a,进而证明P2。

如何满足P2 b ^b b,我们考虑证明我们的情况拥有P2 b ^b b。我们假设一旦number m m m,value v v v的提议被选定,那么所有number n > m n > m n>m的提议都拥有value v v v。我们使用归纳法来证明 n n n的情况,因此我们可以证明number n n n拥有value v v v在额外的假设情况:对所有提议number in m . . ( n − 1 ) m..(n-1) m..(n1)拥有value v v v i . . j i..j i..j的含义是i到j的所有数字的集合。在已经有number m m m的请求被选定(chosen)的情况下,必然有集合 C C C由一个majority组成,而 C C C中的每一个acceptor都接受它。结合归纳法,从m的假设可以推出:

​ 对于number in m . . ( n − 1 ) m..(n-1) m..(n1)的接受提议的acceptor集合 C C C,每一个acceptor的提议都拥有value v v v

而为了实现任何由acceptors的多数派组成的集合 S S S包含至少一个 C C C中的成员,我们可以通过以下条件来确保number n n n,value v v v

P2 c ^c c 对于任意的 v v v n n n,如果一个value v v v,number n n n的提议被发表,那么必然存在一个包含大多数acceptors的集合 S S S满足两个条件之一(a)S中没有一个acceptor接受过小于n的提议(b) v v v是acceptor接受过的number小于n的number最高的提议的value。

我们可以通过维护P2 c ^c c的不变性来满足P2 b ^b b

为了维护P2 c ^c c的不变性,proposer想要发表number n n n的提议就必须获取到小于 n n n的number最高的提议,这个提议已经或者将要被其他acceptor所接受。获取那些已经被接受的proposal已经足够简单了;预测未来的接收情况是困难的。为了避免对未来的预测,proposer通过获得不会有这样的接受情况的承诺来进行控制。换句话说,proposer要求acceptor不要接收任何number小于 n n n的提议。以上内容导出了提议发送的算法:

  1. proposer选择一个number n n n的提议,并向一些acceptor集合的每个成员发送一个请求,希望得到如下回复:

    1. 承诺不再接受number小于 n n n的提议
    2. 如果拥有的话,返回已经接受到的小于n的最高的number

    我愿称呼这种请求叫 p r e p a r e prepare prepare request with number n n n

  2. 如果propser获得来自大多数acceptors的请求的回复,那么将发布一个number n n n,value v v v的提议, v v v是获得的回复中数字最大的value,如果没有回复返回,proposer可以任意选择一个值。

一个proposer发表一个提议,需要发表一个请求给acceptor并被大部分所接受。(接受请求的acceptors和接受提议的acceptors不需要是相同的集合)。让我们称呼这位一个 a c c e p t accept accept request。

以上描述的是proposer的算法。那么acceptor呢?它可以从proposer那里收到两种request: p r e p a r e prepare prepare request和 a c c e p t accept accept request。一个acceptor可以忽略任何请求而不用担心安全的问题。因此我们只需要讨论它允许回复请求的情况。总是可以回复 p r e p a r e prepare prepare request。对于回应并批准 a c c e p t accept accept request,当且仅当它没有被承诺过[未充分理解]。换句话来说:

P1 a ^a a acceptor可以批准number n n n的提议当且仅当它没回复一个number大于 n n n p r e p a r e prepare prepare request

显而易见P1 a ^a a包含了P1。

现在我们得到了一个完整算法去选择一个value,这个value满足我们要求的安全属性–假设提议的编号唯一。通过一个小优化就可以得到最终的算法。

设想一个acceptor接收到一个number n n n p r e p a r e prepare prepare request,但是它已经回复了编号大于 n n n p r e p a r e prepare prepare request,于是就承诺不接受任何编号为 n n n的新请求。在这时,acceptor就不再回复这条编号为 n n n的新请求,也就等价于它不接受编号为 n n n的请求。就此我们允许一个acceptor去无视掉这样一个 p r e p a r e prepare prepare request,还可以忽略已经批准过的议案的prepare请求。

有了这些优化,acceptor只需要记住保存已经被接受的number最大的提议以及number最大的 p r e p a r e prepare prepare request。因为P2 c ^c c需要保证不变性而不需要在意失败,acceptor必须记住它的信息即使在出现故障然后重启后。注意,proposer可以在任意时候抛弃一个提议并忘记它的任意信息,只要它永远不要用相同的编号来提出另一个提议。

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

阶段一 (a)proposer选择一个提议编号 n n n,并发送一个number n n n p r e p a r e prepare prepare request给大多数acceptors。

(b)如果接受到的 p r e p a r e prepare prepare request的编号 n n n大于它已经回应的任何 p r e p a r e prepare prepare request,那么它就会回应请求:不再接受其他number小于 n n n的提议以及已经接受的number最大的提议。

阶段二 (a)如果proposer接收到大多数acceptor关于number n n n p r e p a r e prepare prepare request的回复,接下来它会发送给这些acceptor一个number n n n,value v v v a c c e p t accept accept request, v v v是获得的回复中数字最大的value,如果没有回复返回,proposer可以任意选择一个值。

(b)如果acceptor接收到关于number n n n回复的 a c c e p t accept accept request,它会接受这个提议除非它已经回复一个编号大于 n n n p r e p a r e prepare prepare request。

proposer可以提出多个提议,只要它任何时刻遵循以上算法。它也可以在协议过程中的任意实课抛弃一个提议。(可以保证正确性,即使请求和/或提议的回复在提议被抛弃了很久在抵达。)对于一些想要尝试去发布更高编号的提议的proposer来说这可能是一个好的解决方案。所以,如果acceptor无视掉 p r e p a r e prepare prepare a c c e p t accept accept request因为它已经接收到一个编号更高的 p r e p a r e prepare prepare request,此时它可能需要告诉proposer,谁接下来需要抛弃这个提议。这是一个性能优化,而不影响它的正确性。

2.3 获取被选定的value(Learning a Chosen Value)

在获取到被选定的value之前,learner需要找到被大多数acceptor所接受的提议。一个显而易见的算法是对于每个acceptor,在它们接受一个提议的时候,广播所有learner,发送这个提议。这允许learner去尽快找出被选定的(chosen)value,但这要求每个acceptor去通知每个learner–需要的消息个数等于acceptor数量和learner数量的乘积。

基于非拜占庭失败假设,一个learner可以更容易的从另一个learner获取已经被选定的value。我们可以将acceptor的回复情况回应给一个主learner,主learner反过来可以将被选定的value告诉其他learner。为了让所有learner都获取到被选定的值,此处增加了一次额外的信息传递。这也会降低它的可靠性,在主learner失效的时候。但是它只需要acceptor数量与learner数量的和的请求消息数量。

更普遍的,acceptor获取信息可以从多个主learner获得,每个主learner都在一个value被选定时都告诉所有learner。主learner越多越可靠,但通信的代价也会增加。

由于存在信息丢失,一个被选定的value可能没有learner知道。learner可以向acceptor询问已经批准的提议,但acceptor的故障可能会导致无法知道多数派是否接受一个特定的提议。在这种情况下,learner要找出value是否被选定,可以根据上述的算法通过让proposer发布一个提议。

2.4 流程/活锁(Progress)

很容易去构造这样一种情景,两个proposer持续的发布一系列编号递增的议案,导致没有一个会被选择。proposer p p p完成提议number n 1 n_1 n1的1阶段。另一个proposer q q q完成提议number n 2 > n 1 n_2 > n_1 n2>n1的1阶段。proposer p p p的提议number n 1 n_1 n1的2阶段的 a c c e p t accept accept requests会被无视因为acceptor承诺不接受任何小于 n 2 n_2 n2的提议。因此,proposer p p p接下来开始用新的提议number n 3 > n 2 n_3 > n_2 n3>n2并完成1阶段,导致proposer q q q的2阶段的accept被忽略,如此反复运行。

为了保证流程的顺利进行,需要选举一个主proposer来作为唯一的提议发起人。如果主proposer能够与大多数acceptor成功交流,并且成功使用一个编号比过去使用的编号都大的提议,也就将可以成功发送一个能被接受的提议。而在了解到请求有更高的提议编号时,通过抛弃请求并再次尝试,主proposer最终可以选择到一个足够高的提议编号。

为了使系统中足够多的部分(proposer、acceptor、交互网络)运行正常,可以选举单个主proposer来保持系统的活力,这个著名的结论由Fischer, Lynch, and Patterson得出,选举主proposer的可靠算法可以用随机化或者实时(real time)–比如使用超时(timeouts)。但是,安全性都能得到保证不管选举的成功与否。

2.5 实现(The Implementation)

paxos算法假定了一组网络进程。在其共识算法中,每个进程都会扮演着proposer、acceptor、learner。算法会先选择一个leader,去扮演着主learner和主proposer的角色。paxos一致性算法正如上面描述的一样,请求和回复都会以ordinary消息(messages)的形式发送。(为了避免混淆,回复信息也会同样标记相关的提议编号)。使用稳定的持久化存储可以保证acceptor故障后也能记起必要的信息。acceptor在发送响应之前也会对该响应进行记录。

最后剩余的部分是描述保证提议编号的唯一性的机制了。proposer从互不相交的集合中选择提议编号,这样不同的proposer就永远不会提出相同编号的提议了。每个proposer都持久化的存储已经提出的最高的编号,并使用一个更高的提议编号来开始阶段1。

3 实现状态机模型

实现分布式系统的简单方式是一系列客户端发送命令给服务器中心。这个服务器可以看作是根据一定顺序执行客户端命令的确定状态自动机。这个状态自动机保存它的当前状态,并在每接收到一个命令时就会执行相关步骤,达到一个新的状态并输出。举个例子,银行的分布式系统的客户端可能是出纳员,这个状态自动机可能包含所有用户的账户余额。一次取款操作当前仅当账户内的余额大于取款值时,才会被状态自动机所执行,并且输出之前与当前的余额。

使用单个服务器中心的实现是不可靠的。因此我们需要使用一系列的服务器,每一台自主的实现一个状态自动机。因为这种状态自动机是确定的,所有服务端在接受到相同序列的命令时,会有相同的输出和状态序列。因此客户端可以使用任意一个服务端作为自己发出命令的输出响应。

为了保证所有服务器执行的是相同的命令序列,我们实现一系列独立进行的paxos一致性算法的例子,状态自动机命令序列的第i个状态表示第i个例子选定的value。在算法的每个例子中每个服务器担任所有角色(proposer,acceptor,learner)。现在,我们假设服务器的集合是确定的,那么所有一致性算法的实例都使用相同的agents集合。

正常的流程情况下,会有单个服务器被选举为leader,作为一致性算法所有实例的主proposer存在(唯一可发布提议)。leader接受客户端的命令,并且有权决定每个命令发生的顺序。如果leader决定让中心客户端的命令作为第135个命令,那么这个命令就会作为这个一致性算法的第135个实例。这通常情况下这都能成功。但可能失败比如因为故障,或者其他服务器认为自己是leader,并且在第135个命令也有它自己的想法。但在这个例子中,一致性算法就是要确保第135条至多被一条命令所选定。

paxos一致性算法有效性的关键在于,提议直到2阶段才会被选定。回忆一下,在proposer完成算法的1阶段后,才可以得到所需要提议的value或者可以选择任意输出value。

我现在将描述在正常流程下paxos状态自动机是如何工作的。在下个部分,我还会讨论可能出现的错误情况。再考虑下在旧的leader故障后,新的leader被选举出来时会发生什么样情况。(系统启动时没有命令会被提出的特例。)

被选举出来的新的leader,作为原来一致性算法的实例的learner中的一员,会知道大部分已经被选定的命令。假设它已经知道命令1-134、138、139,也就等价于实例1-134、138、139的value。(后面部分我们会知道为什么在这个命令序列会有一段间隔)然后它会执行135-137和大于139的实例的1阶段。(后面部分也会说明怎么做到)可以推断目前已执行命令的结果可推断出于135和140实例的value,但是其他实例的提议的value仍无法确定。leader接下来会执行135和140实例的2阶段,并选择135和140的命令。

leader和其他已经获取leader所有命令的服务器,都执行了1-135的命令。然而,它仍然不可执行138-140的命令,即使已经知道命令的内容,因为还必须选定136和137命令。leader可以把从客户端获取的接下来两个命令作为136和137的命令。此外,我们可以通过添加一个特殊不发生改变的“no-op”命令,用来立刻填充此处的间隙[未充分理解]一旦这些noop命令被选定后,138-140的命令就会被执行。

现在1-140的命令都被选定了。leader也完成了大于140的实例的1阶段,那么任意决定这些实例2阶段位于的value了。比如将客户端的下一条命令编号作为141,并提议141实例的2阶段。再把吓一跳命令编号为142,以此类推。

在获取到141命令是否被选定(chosen)之前,leader可以提出命令142。可能出现的情况时发布命令141的消息全部丢失,然后在所有其他服务器获取到141命令前就已经选定了142命令。当leader在141实例中获取命令的回复失败了,它会重传这些信息。如果一切顺利,它提出的命令将被选定。但是,它也可能仍然失败,这就会导致在被选定的命令序列中留下一段间隔。通常情况下,假设leader可以预取 α \alpha α条指令–同理,它可以同时发布 i + 1 i+1 i+1 i + a i+a i+a命令在命令 1 1 1 i i i被选定后。而此时最大可以产生 α − 1 \alpha-1 α1的间隔。

被选定的新的leader要为一致性算法的许许多多的实例执行1阶段–在上面的情景中,是对135-137和大于139的实例。leader可以通过发送一条合理的短信息到其他服务器,并使用相同的提议编号。在1阶段中,acceptor当且仅当接收到proposer的2阶段消息时,会回应多余简单OK的额外的信息。(在情景中,这只表示135和140实例)因此,一个作为acceptor的服务端可以用一条简单合理短小的消息来回复所有实例而不用担心会导致什么问题。

因为leader的失效并选举一个新leader应该是小概率实践,有效执行一条状态自动机命令的开销–或者叫实现命令/value的一致性–仅仅是一致性算法的2阶段的开销。并且可以证明,在允许失效的范围内,所有的同类(一致性)算法中,paxos一致性算法的2阶段具有最小可能的代价。因此,paxos算法在本质上是最优解。

上述关于系统正常流程的讨论假设总是有单个leader,而除去在当前leader故障到选举出新的leader的一小段时间。在异常情况下,可能leader的选举会失败。此时如果没有服务器担任leader,会导致没有新的命令被发布。而如果多个服务器认为自己是leader,对于同一个算法实例,它们将都能提出提议,这回导致没有值被选定。虽然如此,但安全性得到了保证–两个不同的服务器永远不会再第i个状态机命令的选择上达成一致。单个leader的选举的意义只在于确保流程的顺利进行。

如果服务器的集合可以改变,那么必须有方法来确定一致性算法的实例分别对应哪个服务器的实现。最简单的方法是通过状态机自己进行检测。当前的服务器集合可以作为状态的一部分,也可以被原生的状态机命令所修改。在执行完第i条状态机的命令后,我们可以允许leader预取 α \alpha α条指令,通过让server集合执行一致性算法的第 i + α i+\alpha i+α条实例。[未充分理解]这样就允许你通过简单实现就可以解决多变的复杂重构算法。[未充分理解]

问题

证明:P2 c ^c c证明P2 b ^b b

个人观点:

根据论文中P2 b ^b b证明P2 c ^c c之间的话,可得只需要证明P2 c ^c c可以证明

P s _s s:任何由acceptors的多数派组成的集合 S S S包含至少一个 C C C中的成员。但实际过程中,我们需要找出这个成员,也就需要证明:P s ′ s^{'} s:任何由acceptors的多数派组成的集合 S S S,能够找出至少一个 C C C中的成员。

在number m m m,value v v v的提议被选定时,对于number m + 1.. n m+1..n m+1..n,P s _s s已成立。(条件①)

有一个条件,通过P2 c ^c c得出的value v v v,是目前接受提议value的最大值。(条件②)

条件②证明:若value v v v是P2 c ^c c(a)得出,说明目前没有提议通过,为最大值;若value v v v是P2 c ^c c(b)得出,由反证法,假设存在一个通过提议value v ′ > v v^{'}>v v>v,并且未在集合 S S S中,由 S S S为多数派,则通过提议value v ′ v^{'} v的多数派一定与 S S S有交集,假设不成立。综上所述,value v v v是目前接受提议value的最大值。

number m m m,value v v v的提议被选定的value是非递减的。(条件③)

条件③应该是隐含的,我也忘记这点是什么时候出现了。

综上,有条件③,可以得出在number m m m,value v v v的提议被选定时,此时的value v v v为当前value的最大值;条件①保证了每次accept的集合中一定包含有value v v v的acceptor;条件②则保证了能从acceptor中选出value v v v,也就找出了P s ′ s^{'} s中的 C C C中的成员。

即证明P s ′ s^{'} s成立,进而证明命题。

参考链接

状态自动机学习链接

论文翻译参考链接

第三段部分参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值