《Paxos made simple》译文

本文深入浅出地解析了Paxos算法,一种用于分布式系统中实现一致性的重要算法。介绍了算法的基本原理,包括共识算法的过程、实现状态机的方法,以及如何在分布式环境中达成一致性和活性。同时探讨了算法在实际应用中的优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《Paxos made simple》译文
Paxos Made Simple 译文

摘要

  用直白英文表达的Paxos算法是非常简单的。

目录

1 介绍

2 共识算法

2.1 问题描述
2.2 选值
2.3 学习已选定的值
2.4 过程
2.5 实现

3 实现状态机

参考文献

1 介绍

  实现在分布式容错系统中的Paxos算法被视为是难以理解的,或许是对大多数读者来说,原始发表是希腊语。事实上,这是最简单易懂的分布式算法。它的核心是一种共识算法— “会议”算法。下一节将显示,这个共识算法几乎不可避免地遵循我们希望它满足的特性。最后一个章节解释了完整的Paxos算法,该算法通过将协商一致直接应用于国家机制来构建分布式系统的计算机方法来获得–这种方法应该是众所周知的,因为它可能是关于分布式系统理论的最常引用文章的主题。

2 共识算法
2.1 问题描述

  假设一个线程集合能提出值。共识算法就是要保证在这些被提出的值中只有一个被选中。如果没有提出任何值,那就应该没有被选中。如果有一个值被选中,其它的进程应该能够学习这个所选的值。安全性要求,共识算法:

  • 只有被提出的值才可能被选中,
  • 只有一个值被选中,
  • 除非一个值被选中,否则进程无法知道已经被选中的值。

  我们不试图详细描述活性的要求。然而,它的目标是确保最终一些值被选中,如果一个值被选中,那么进程能最终学习这个值。
  共识算法有三种角色:提案者、接受者、学习者。在具体实现中,一个线程可能担任多种角色,但是在此处我们不关心从角色到线程的映射。
角色通过发送消息与其他角色交流。我们使用普通的异步,非拜占庭模式,在此模式里:

  • 角色以任意速度运行,可能失败停止,也可能重启。因为所有角色都有可能在一个值被选中之后失败然后重启,除非这些信息被失败并重启的角色记下来,否则这个问题是无法解决的。
  • 信息能以任意长度被传递,复制、丢失,但是不能被篡改。
2.2 选值

  选值的最简单办法就是只有一个接受者。提案者向接受者发起提案,接受者选择它接受到的第一个提案值。虽然简单,但是这种方法是不可取的,因为接受者故障后会导致下一步操作失败。
  所以,我们尝试其他的选值方案。不采用单个接受者方案,这次我们使用多个接受者。提案者向一个接受者集合发送提案值。一个接受者可能会接受这个值。当足够多接受者接受这个值时,这个值就被选定了。那么多少接受者算是足够多?为了确保只有一个值被选中,我们使大多数接受者构成这个足够多的接受者集合。因为任意两个大多数集合至少有一个接受者是公共的,而接受者最多只能接受一个值。(有一个明显的概括,大多数已经在许多论文中观察到,显然从[3]开始。)
  在没有故障或者消息丢失的情况下,当只有一个提案者仅提出一个值时,我们希望这个值被选中,这就需要以下要求:

P1. 接受者必须无条件接受它按收到的第一个提案

  但是这个要求会引发一个问题。几个不同的提案者同时提出几个提案值,会导致这种情况产生,每个接受者都接受了提案值,但是没有一个提案被大多数接受者接受。甚至当只有两个提案值时,它们都被一半接受者接受,单个接受者故障都可能会导致不知道哪个值被选中。
  P1和大多数接受者接受一个值那么该值才能被选中的要求,暗含着接受者必须能接受多个提案。我们通过为每个提案标记号码来追踪接受者接收过得多个提案,因此提案就由一个提案号和提案值构成。为防止混淆,我们要求每个提案都有不同的提案号。再此我们不讨论它是怎么实现的,我们只是假设它。当提案者提出的值被大多数接受者接受后,这个值就被选定了。在这种情况下我们说这个提案(也就是它的值)被选中。
  我们允许多个提案被选中,但是必须保证所有被选中的提案有相同的值。通过对提案编号的归纳,就足以保证:

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的提案被选中。然后展示其余任何n>m 的提案值也是v ,为了使证明更简单我们直接使用n,我们要在其余发起的提案号为m…(n-1)的值也为v的前提下证明,提案号为n 的提案值也是v,此处i…j表示从i到j的一系列编号。提案m被选中,那么就意味着由大多数接受者构成的集合C中每一个接受者都接受了一个提案。把这个和之前的假设结合起来,假设m被选中就暗含:
  每一个集合C中的接受者接受提案编号在m…(n-1)的提案,其值也是v。
  因为任何由大多数接受者构成的集合S,都至少包含C中的一个成员,我们可以通过确保保持以下不变式来得出编号n的建议具有v值的结论:

P2c. 对任意n和v 如果一个提案号为n,提案值为v 的提案被提交,那么包含了大多数接受者的集合S,要么(a)S中的接受者没有接受到比n还小的提案,要么(b)S接受的所有比n 小的提案中,提案号最大的提案值为v。

  我们通过保持P2C的不变性因而满足P2a.
  为了保持P2C的不变性,如果一个提案已经或者将被大多数接受者接受,提案号为n的提案想要提交就必须学习比n小的最大提案号对应的提案值。学习已经被接受的提案是非常简单的;预测未来要接受的提案是困难的。并不是试图预测未来,提议者控制它通过给出一个承诺,即不会有任何这样的接受。换句话说,提案者要求接受者不接受任何比n小的提案。以下是发起提案算法:
1.提案者选择一个新的提案编号并且发送请求给一些接受者集合中的每一个接受者,等待其回应:
(a) 承诺不再接受比n小的提案;
(b) 如果存在,返回已经接受过比n小的最大提案。
把这样的请求称为编号为n的准备请求
2.如果提案者接受了大多数接受者的响应,然后发起一个提案号为n,提案值为v的提案。v是响应中最大提案号的提案值,或者如果接受者的没有回应任何提案,那么v就是提案者自己确定的值。

  提案者发起提案,并发送给一些接受者集合回应这个提案已经被接受。(这些接受者集合不需要与最初的接受者集合一致),我们成这个过程为接受请求。
  以上是关于提案者的算法,那么接受者算法呢?它能接受提案者发起的两种请求:准备请求和接受请求。接受者为了不妥协安全性能忽略任何请求。我们只需要说明当它被允许响应请求时,它能响应准备请求和接受请求,当它没有承诺不接受提案时,它能接受提案。换句话说:

P1a 接受者能接受提案号为n的提案,如果它还没响应过比n更高的准备请求。

观察可知P1a包含P1
  现在已经有了能满足所需的假定唯一的提案号安全性要求的选值完整算法。通过一些小的优化来得到最后的算法。
  假设一个接受者收到编号为n的准备请求,但是它已经响应了其他编号高于n的准备请求,因此依据承诺它不能接受编号为n的请求。因此,接受者没有理由对新的准备请求作出答复,因为它将不接受提案者发出的编号为n的提案。所以我们令接受者忽略这样的准备请求,我们也同样让它忽略它已经接受的提案的准备请求。
  有了这样的优化,接受者只需要记住它已经接受的最高编号的提案和它响应的最高编号的准备请求的编号。P2C要求不论任何形式的失败,接受者都必须记住这些信息,即使它失败了然后重启。值得注意的是,提案者可以放弃任何一个提案并且忘记与之相关的一切,只要它不尝试以相同的提案号发起一个提案。
把提案者和接受者放在一起,该算法就能分为以下两个阶段:

阶段1
(a) 提案者选择一个提案号n,发送一个有提案号n的准备请求给大多数接受者。
(b) 如果一个接受者收到的编号为n的准备请求优于它已经响应过得任何准备请求,那它就回应该请求,承诺不再接受任何编号小于n的提案,并回复它已经接受的提案(如果存在)。
阶段2
(a) 如果提案者收到大多数接受者关于它编号为n的接受请求的回应,它就给这些接受者发送一个编号为n,值为v的接受请求,v是收到的回应中编号最高的提案值,或者如果没有回应提案,那v可以是任意值。
(b) 接受者收到提案号为n 的接收请求,它接受该提案,除非它已经响应了比n更高的准备请求。

  提案者可以发起多个提案,只要每个提案都符合以上算法。它可以在协议的任何时候放弃提案。(保持正确性,即使一个提案的请求或者响应在该提案被放弃很久之后到达)当提案者开始尝试发起编号更高的提案时,放弃一个提案时明智的。因此当一个接受者忽略准备或者接受请求,是因为它已经接受了更高编号的准备请求,然后它应该通知提案者放弃自己的提案。此处的性能改进并不影响正确性。

2.3 学习已选定的值

  为了学习已被选中的值,学习者必须找到已被大多数接受者接受的提案。一种显而易见的算法是对于每一个接受者,不论何时,当它接受一个提案时,就响应给所有学习者,像它们发送提案。这使得学习者能尽可能快的发现被选定的值,但是这需要每一个接受者响应给每一个学习者----响应的数量的等于接受者的数量乘以学习者的数量。
  非拜占庭失败的假设使得一个学习者容易从其他学习者处发现一个值已经被接受。我们可以让接受者响应它们的接受给一个特殊的学习者,当一个值被选定时,它可以依次通知其他学习者。这个办法需要额外的一轮来使所有学习者发现已选定的值。这样也缺乏可靠性,因为特定的学习者可能会失败。但是这个方法需要的响应数量等于接受者和学习者的数量之和。
  一般来说,接受者可以响应它们的接受内容给特定的学习者集合,它们中的任意一个学习者都可以通知其他学习者已经被选定的值。使用的特定学习者集合越大可靠性就越高,同时通信复杂度的代价也越大。
  由于消息丢失,没有学习者发现被选定的值。学习者可以询问接受者它们已经接受的提案,但是一个接受者的失败可能使学习者无法知道是否大多数接受者已经接受了某一特定的提案。在这种情况下,学习者只有在一个新的提案被选定后才能知道被选定的值。如果一个学习者需要直达是否一个值被选定,它可以让提案者发起一个提案,使用之前描述的算法。

2.4 过程

  容易构建这样的场景:两个提案者各自不断依次发起提案号不断增加的提案,但是没有一个提案被选中。提案者p完成了提案号为n1的阶段1。另一个提案者p2接着完成了提案号n2>n1的阶段1。提案者p1的提案号为n1的阶段2接受阶段被忽略,因为接受者承诺不接受任何比n2小的提案。所有提案者p开始发起并完成提案号n3>n2的提案阶段1,造成提案者q的阶段2的接受请求被忽略。等等。
  为了保证过程,一个特定的提案者被选定作为唯一能发起提案的。如果这个特定的提案者能与大多数接受者成功通信,如果它使用的提案号比它之前使用的提案号都大,那么它就能发起一个可被成功接受的提案。当了解到有更高提案号的请求这个特定的提案者可以放弃当前提案并且重新尝试,这样特定提案者将最终选择足够大的提案号。
  如果足够的系统(提案者、接受者、通信网络)能够正常运行,活性就能由最终选定一个提案者完成。Fischer、Lynch和Patterson[1]的著名结果表明,用于选择提案者的可靠算法必须使用随机性或实时性,例如,使用超时。然而,不论选举是成功还是失败,安全性都能被保证。

2.5 实现

  Paxos算法假设了一个进程网络。在它的共识算法中,任何进程能扮演提案者、接受者、学习者的角色。这个算法选择一个领导者,它扮演特定提案者和学习者的角色。Paxos共识算法正是以上描述的算法,其中请求和响应可以作为普通的消息来发送。(为防止混淆,响应信息使用相应的提案号标记)在故障期间保障稳定的存储,用于维护接受者必须记住的信息。接受者在发送响应之前将它计划响应记录在稳定的存储中。
  剩下的只是描述一种机制,以确保不会有两个提案以相同的编号发布。不同的提案者从不相交的编码集合中选择它们的提案号,因此两个不同的提案者不可能发起有相同提案号的提案。任意提案者记住(在稳定存储中)其尝试发起的最高提案号的提案,并以一个比它已经使用过的提案编号更高的提案编号开始第一阶段。

3 实现状态机

  实现分布式系统的一个简单方法就是向中央服务器发送命令的客户机集合。服务器可被视为是确定状态机,以一些序列完成客户机的命令。状态机有当前状态;它执行一个步骤,将一个命令作为输入,生成一个输出和新的状态。例如,分布式银行系统的客户机可能是提款机,状态机的状态可能由所有用户的账户余额构成。如果并且仅当余额大于提取的金额时,执行减少账户余额的状态机命令来执行提取,生成旧的和新的余额作为输出。
  如果服务器故障,使用单个中央服务器的实现就失败了。因此我们使用服务器集合,其中的每个服务器都单独实现状态机,因为状态机是确定的,所有服务器如果执行相同的命令就会相同生成的状态序列和结果。然后,发出命令的客户机可以使用任何服务器为其生成的输出.
  为了保证所有服务器执行相同的状态机命令,我们实现了paxos共识算法的一系列独立实例,其中第i个实例选择的值是序列中的第i个状态机命令。每个服务器在每个算法实例中扮演所有角色。现在,我假设服务器集是固定的,所以共识算法的所有实例都使用相同的代理集。
  在常规操作中,单个服务器作为领导者,在所有共识算法实例中以独一无二的的提案者角色(唯一尝试发起提案的)来运行。客户端发送命令给领导者,领导者决定每个命令在序列中的出现顺序。如果领导者决定某一命令应该是第135个命令,它就尝试使这个命令成为被选作第135个共识算法实例的值。通常情况下都会成功,它可能会失败因为故障,或者因为其他服务器也认为自己是领导者并且对第135个命令提出不一样的值。但是共识算法确保最多一个命令会被选作第135个命令。
  这种方法效率的关键在于,在Paxos协商一致算法中,要到第二阶段才会选择要提出的值。回忆一下,在完成提案者算法的第一阶段后,被提交的提案值要不是确定的,要不是提案者可以提出的任意值。
  现在我们描述一下在Paxos状态机中是如何实现常规操作的。稍后讨论什么会出错,思考在前一个领导者失败和新领导者被选出后会发生什么。(系统启动时一个特殊情况,此时没有任何命令被提交)
  新领导者作为共识算法所有实例的学习者应该知道大多数命令已经被选定。假设它知道命令1-134、138和139,即在协商一致算法的实例1-134、138和139中选择的值。(我们会看到如何在命令序列的产生这样的空白)然后,它执行实例135-137和大于139的所有实例的第一阶段。(我在下面描述如何做到这一点。)假设执行的结果是确定了实例135和140提交的值,但是在其他实例中建议值不受限制,领导者执行实例135和140的第二阶段,因此选定了命令135和140。
  领导者和其他学习领导者知道的命令的服务器能够执行命令1-135,。然而,它不能执行命令138-140,因为命令136和137还没有被选定。相反,我们通过提交向命令136和137 那样提交一个不会改变状态的“no-op”命令来填补空白。(通过执行算法实例136和137的第二阶段来实现这一点)一旦这些no-op命令被选定,命令138-140就可以被执行。
命令1-140现在可以被选定了。领导者完成所有优于共识算法实例140的实例阶段一,在这些实例的第二阶段自由的提出任意的提案值。它将编号为141的实例分配给下一个客户端请求的命令,把它作为共识算法实例141的第二阶段的值来提交。它提交下一个接收的客户端命令为命令142,等等。
  领导者在学习了它选定的命令141后才能提交命令142.它发送的全部有关提交命令141的信息可能丢失,对于命令142被选定之前其他任何服务器都必须学习领导者在命令141提交的内容。当领导者无法接收到实例141第二阶段消息的期望响应时,它将重传这些消息。如果一切顺利,这个提交的命令就被选定了,然而,如果失败,将在被选定的命令序列留下一个空白。通常,假设领导者能提前获得α个命令,也就是说,在命令1到i被选定之后,它能通过i+α提交命令i +1。然后出现高达α-1 个命令的空白。
  新选定的领导者针对无限多共识算法的实例执行阶段一,在前面的场景中,是针对实例135-137和大于139 的所有实例。对于所有实例使用相同的提案号,通过向其他服务器发送合理的短消息来实现这一点。在阶段一中,当接受者已经接受过其他提案者第二阶段的消息后,它的回应不仅仅是简单的OK。(在这种情况下,只适用于实例135和140的情况)因此服务器(充当接受者)能够用一个合理的短消息来回应所有实例。因此执行这些无限多实例的阶段一是没有问题的。
  因为领导者失败和选举新的领导者应该是罕见事件,执行状态机命令的效率代价,也就是对命令和值形成共识的代价就是共识算法第二阶段的执行代价。可以表明,在存在故障的情况下,Paxos共识算法的阶段二具有用于达成一致的任何算法的最小可能成本。因此Paxos算法基本上是最优的。
  系统的常规操作讨论中假定除了前一个领导者失败和选举新领导者的简短时间之外,只有一个领导者。在非正常情况下,领导者选举可能会失败。如果没有服务器被选为领导者,就没有命令可以被提交。如果多个服务器认为他们是领导者,它们都可以对共识算法的相同实例提交提案值,这可能会造成没有值被选定。然而安全性是被维护的-对第i个状态机命令选定值上,两个服务器永远不会不同意。需要选举单个领导者来确保进展。
  如果服务器集合能够改变,那么久需要有方法来确定哪些服务器来实现哪些共识算法的实例。解决这个问题最简单的办法就是通过状态机本身。当前服务器集合可以只作为状态的一部分,使用常规状态机命令来改变。我们可以使领导者得到前面α个命令,通过使执行了共识算法实例i+α的服务器集合被指定为执行了第i个状态机命令之后的状态。这允许对任意复杂的重构算法进行简单实现。

参考文献:

[1] Michael J. Fischer, Nancy Lynch, and Michael S. Paterson. Impossibilityof 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 consensuswhen 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 New32(2) (June 2001).
[3] Leslie Lamport. The implementation of reliable distributed multiprocesssystems. Computer Networks, 2:95–114, 1978.
[4] Leslie Lamport. Time, clocks, and the ordering of events in a distributedsystem. 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.

自翻,希望对大家有帮助。
原文链接https://lamport.azurewebsites.net/pubs/paxos-simple.pdf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值