【编者的话】本文是Quora上关于Paxos算法的回答,两位答者分别从不同的角度描述Paxos算法。Vineet Gupta的回答细致入微,更偏向理论。Russell Cohen用具体的例子讲解Paxos算法,相辅相成。
考虑到很多努力解决共识问题但又存在缺陷的解决方案,我认为Paxos算法很容易理解,所以我会好好谈谈它。
达成共识的一个直观方法就是采用结婚誓词:
现在假设这场婚礼不是两个人之间了,而是有点像罗伯特·乔丹的 时间之轮系列
中 艾尔 民俗中发生的那样:一位或者更多的艾尔女人可以成为 first-sisters ,而男人要么把她们全部娶回家要么一个也不娶。在艾尔人眼中,婚姻誓词也许是下面这样的:
如果任何一个将会成为配偶的艾尔人不回应“我愿意”,这场婚礼将无法进行。
计算机科学家把上面的现象称为两阶段提交。
要注意的是票只能投给(协调器)提出的值-每个节点只能说是或否。节点不能再提出一个可供选择的值。如果一个节点想提出自己的 值,它需要开始它自己的2PC。算法工作原理很清晰-由节点来决定某一个节点提出的值。它也不是非常低效的,对于N个节点,将交换条3N消息。
但是如果一个节点崩溃了会发生什么?例如,假设在阶段一协调器将提议的值发送给N个节点中的部分但不是全部,然后它崩溃了。(这是会发生什么?)
如果阶段二中的协调器未能把所有的提交信息发送给全部节点而只是部分节点后就崩溃了,相似的问题依然存在。我们可以让另一个节点接管协调器职责观察时间超时来解决部分存在的问题。这个节点会和其它节点取得联系并获得它们的投票情况(要求它们必须投票)以及推动事务完成,但这一过程中进一步参与者可能发生故障,同时事务可能永远不会恢复。我们的底线-在节点故障的情况下2PC无法可靠地操作。
2PC的关键问题是,万一协调器崩溃了,没有节点具备足够的信息来完成整个协议。这一点可以通过添加额外的步骤来解决:
1. 阶段1-和(2PC)相同-协调器给所有的节点发送一个值。
2. 阶段2-新的步骤-一旦从上一步中所有节点都接收到“是”,协调器发送出“准备提交”消息。我们期望的是节点能够执行可以撤消的工作,而且没有什么是不能撤消的。每一个节点向协调器确认它已经接收到“准备提交”消息了。
3. 阶段3-类似2PC中阶段二-如果协调器从所有节点接收到关于“准备提交”的确认信息,它就继续工作,将投票的结果发送给所有的节点要求他们提交。但是,如果所有节点都不确认,协调器会终止事务。
现在如果协调器在任何时刻崩溃,任何参与者都可以接管协调器的角色并查询来自其它节点的状态。
因此3PC能够很好地工作尽管有节点故障。这是以在N个节点添加一个新的步骤为代价的,它导致了较高的延时。
3PC在网络分区情况下存在不足。假设所有收到“准备提交”信息的资源管理都在分区的一侧,其余的都在另一边。现在这会导致每个分区都选择一个恢复节点,这两个恢复节点要么提交事务,要么终止事务。一旦网络分区被移除,系统会得到不一致的状态。
先说重要的事-考虑下3PC,我们还需要更好的算法吗?3PC唯一的问题是网络分区,真的吗?首先,我们假设网络分区是唯一的问题(并不是,下面我们会看到)。在网络分区的情况下,正确性真的是值得解决的问题吗?今天,在云计算和互联网规模的服务下,其中的节点有可能在大陆的不同侧或者跨越了大洋,我们确实需要分区容错算法。
第二点是网络分区并不是唯一的问题。当我们解决了单个节点永久故障的情况时,更一般的情况是,节点崩溃了,接着它重新恢复并且从崩溃的地方工作。这种 故障-恢复模式
也可以描述一个异步网络模型,这种网络模型中一个节点用来响应消息的时间是没有上限的,因此你不能假设一个节点死了-也许它仅仅是响应缓慢或者是网络缓慢。在这种模型中你不能判断超时。
3PC是 故障-停止
容错,而不是 故障-恢复
容错。不幸的是现实生活中需要的是 故障-恢复
容错,因此我们需要更一般的解决方案。而这正是Paxos的用武之地。
Paxos中的基本步骤和2PC很像:
接收-请求
消息中,接收者可以回复拒绝或接受。 提交
信息。 Paxos与2PC主要不同点在于Paxos不要求所有节点都要同意(才会提交事务),只要大部分节点同意就行。这是一个有趣的想法因为在两个独立的多数节点中至少存在一个正常工作的节点。这确保在给定的循环中,如果大部分节点赞同给定的值,任何随后努力提出一个新值的节点将会获得来自其它节点的值而且这个节点也只会赞同那个值(不会再提出自己的值了)。这也意味着Paxos算法不会阻塞即使一半的节点无法回复消息。
当然也可能发生是领导节点自己故障了。为了解决这个问题,Paoxs在给定的时间点不会只向一个领导节点授权。它允许任何节点(在领导节点故障时)成为领导者并协调事务。这也自然意味着在特定情况下至少存在一个节点能称为领导者。在上述情况下很可能存在两个领导者并且他们发送了不同的值。所以如何达成共识呢?为了在这样的设置下达成共识,Paxos介绍了两种机制:
接受请求
以及提议序列号和值。 接受请求
消息,它只在下面两种情况符合时发送“接受”信息,否则发送“拒绝”: 如果Paxos算法中我们一次只授权唯一一个领导者,同时授权小部分节点,那样会发生什么?所有节点都要投票吗?是的,(这时)我们使用2PC。 2PC是Paxos中的特例 。
正如人们所看到的,在故障容错上Paxos要优于2PC:
Paxos也比3PC更加容错。具体地讲,Paxos是分区容错3PC不是。在3PC中,如果两个分区分别赞同一个值,当分区合并的时候,会留给你一个不一致的状态。在Paxos中,大部分情况下这不会发生。除非某个分区占绝大多数,否则不会达成共识。如果某个分区占绝大多数并达成一个共识,那值就需要被其它分区中的节点接受。
Paxos存在的一个问题是,两个领导者因为处于不同的分区导致不能互相观察,他们会努力向另一方投标,发布一个比先前协议有更高序列号的协议。这可能导致Paxos无法终止。最终这两个互相观察的领导者必须有一个需要做出退让。
这样做是安全和活性间的折中。Paxos是安全的算法-一旦达成共识,赞同的值不会改变。但是,Paxos不能保证处在工作状态-Paxos在稀少的情况下可能不被终止。事实上一个异步一致算法不能被保证既安全又处于 活动状态 。我们称这为 FLP不可能结果 。
本文提供了一个非常清晰的解释和证明:
http://nil.csail.mit.edu/6.824...
我将努力提供一个清晰的总结:
Paxos算法的目的是帮助一些同等的节点就一个值达成一致的协议。Paxos保证如果一个节点相信一个值已经被多数节点赞同,多数节点就再也不会赞同其它值。这个协议被设计使得任何共识必须得到大部分节点的认可。任何将来试图达成共识的尝试,如果成功了也必须经过至少一个节点的认可。
因此,任何已经做出决定的节点必须和多数中的一个节点通信。协议保证节点将能从多数节点赞同的值得到收获。
下面讲述它是如何运作的:
假设我们有3个节点:A,B和C。A将提出一个值"Foo."
Paxos将分3个阶段执行。在每个阶段,必须有多数节点达成一致。
首先,我们来看准备阶段。节点A发送准备请求给A,B,C。Paxos根据序列号来实现它的保证。 准备请求
要求节点承诺:“我永远不会接受序列号比 准备请求
小的提议。”(被询问的节点)回复一个它们之前赞同的值(如果有的话)。(这一点非常重要):节点A必须回应它接收到的最高序列号的值。这一行为提供了保证:先前得到的赞同的值将被保留。
接下来我们进入到接受阶段。A发送一条 接受请求 给A,B和C。接受请求表示:“你接受Foo吗?”。如果伴随的序列号不小于节点先前已经承诺过的序列号或者是节点先前接受的请求的序列号,那么节点将接受新的值和序列号。
如果节点A从多数节点接收到的是“接受”,(Foo)这个值就被确定下来。Paxos循环也会终止不再询问新的值。
阶段三不是绝对必须的,但是如果在生产环境中实现Paxos算法,阶段三会是重要的优化。A收到多数节点“接受”消息后,它发送“已经确定值”消息给A,B和C。这条消息让所有节点知道已经选好了值,这会加快决定值的过程结束。
如果没有这个消息,其它节点将继续提出新的值来了解协议。在准备阶段,它们不断从预先约定的值中学习,一旦它们从协议得到结论,节点就会确认这个协议。
(为了便于理解)我掩盖了一些关键的问题:
1. 所有的序列号必须单调递增,而且不同节点序列号都不同。也就是说,A、B不能用同一个序列号k发送信息。协议要求所有发送的消息必须包含序列号。在准备阶段每个节点都要追踪它遇到的最高接受请求和它承诺的(序列号)最高的值。
2. 故障情况。一次Paxos循环中很可能失败,万一失败了,一个节点会用更高的序列号发起新的提议。
3. 终止情况。我所描述的Paxos版本不一定出现终止故障。对于正常的终止情况,(我描述的)Paxos算法还需要一些调整。
原文连接: Distributed Systems: What is a simple explanation of the Paxos algorithm? (翻译:adolphlwq)
=========================================
译者介绍
adolphlwq,南京信息工程大学本科大四学生,对Docker充满兴趣,喜欢运动。现在正努力充电希望快速进步。