Paxos分析

Paxos算法细节详解(一)--通过现实世界描述算法

最近研究paxos算法,看了许多相关的文章,概念还是很模糊,觉得还是没有掌握paxos算法的精髓,所以花了3天时间分析了libpaxos3的所有代码,此代码可以从https://bitbucket.org/sciascid/libpaxos 下载。对paxos算法有初步了解之后,再看此文的效果会更好;如果你也想分析libpaxos3的话,此文应该会对你有不小帮助;关于paxos的历史这里不多做介绍,关于描述paxos算法写的最好的一篇文章应该就是维基百科了,地址戳这里:http://zh.wikipedia.org/zh-cn/Paxos%E7%AE%97%E6%B3%95

 

在paxos算法中,分为4种角色:

  Proposer :提议者

  Acceptor:决策者

  Client:产生议题者

  Learner:最终决策学习者

上面4种角色中,提议者和决策者是很重要的,其他的2个角色在整个算法中应该算做打酱油的,Proposer就像Client的使者,由Proposer使者拿着Client的议题去向Acceptor提议,让Acceptor来决策。这里上面出现了个新名词:最终决策。现在来系统的介绍一下paxos算法中所有的行为:

  1. Proposer提出议题
  2. Acceptor初步接受 或者 Acceptor初步不接受
  3. 如果上一步Acceptor初步接受则Proposer再次向Acceptor确认是否最终接受
  4. Acceptor 最终接受 或者Acceptor 最终不接受

上面Learner最终学习的目标是Acceptor们最终接受了什么议题?注意,这里是向所有Acceptor学习,如果有多数派个Acceptor最终接受了某提议,那就得到了最终的结果,算法的目的就达到了。画一幅图来更加直观:

 

为什么需要3个Acceptor?因为Acceptor必须是最少大于等于3个,并且必须是奇数个,因为要形成多数派嘛,如果是偶数个,比如4个,2个接受2个不接受,各执己见,没法搞下去了。

为什么是3个Proposer? 其实无所谓是多少个了,1~n 都可以的;如果是1个proposer,毫无竞争压力,很顺利的完成2阶段提交,Acceptor们最终批准了事。如果是多个proposer就比较复杂了,请继续看。

 

上面的图中是画了很多节点的,每个节点需要一台机器么?答案是不需要的,上面的图是逻辑图,物理中,可以将Acceptor和Proposer以及Client放到一台机器上,只是使用了不同的端口号罢了,Acceptor们启动不同端口的TCP监听,Proposer来主动连接即可;完全可以将Client、Proposer、Acceptor、Learner合并到一个程序里面;这里举一个例子:比如开发一个JOB程序,JOB程序部署在多台服务器上(数量为奇数),这些JOB有可能同时处理一项任务,现在使用paxos算法让这些JOB自己来商量由谁(哪台机器)来处理这项任务,这样JOB程序里就需要包含Client、Proposer、Acceptor、Learner这4大功能,并且需要配置其他JOB服务器的IP地址。

再举一个例子,zookeeper常常用来做分布式事务锁。Zookeeper所使用的zad协议也是类似paxos协议的。所有分布式自协商一致性算法都是paxos算法的简化或者变种。Client是使用zookeeper服务的机器,Zookeeper自身包含了Acceptor, Proposer, Learner。Zookeeper领导选举就是paxos过程,还有Client对Zookeeper写Znode时,也是要进行Paxos过程的,因为不同Client可能连接不同的Zookeeper服务器来写Znode,到底哪个Client才能写成功?需要依靠Zookeeper的paxos保证一致性,写成功Znode的Client自然就是被最终接受了,Znode包含了写入Client的IP与端口,其他的Client也可以读取到这个Znode来进行Learner。也就是说在Zookeeper自身包含了Learner(因为Zookeeper为了保证自身的一致性而会进行领导选举,所以需要有Learner的内部机制,多个Zookeeper服务器之间需要知道现在谁是领导了),Client端也可以Learner,Learner是广义的。

 

现在通过一则故事来学习paxos的算法的流程(2阶段提交),有2个Client(老板,老板之间是竞争关系)和3个Acceptor(政府官员):

  1. 现在需要对一项议题来进行paxos过程,议题是“A项目我要中标!”,这里的“我”指每个带着他的秘书Proposer的Client老板。
  2. Proposer当然听老板的话了,赶紧带着议题和现金去找Acceptor政府官员。
  3. 作为政府官员,当然想谁给的钱多就把项目给谁。
  4. Proposer-1小姐带着现金同时找到了Acceptor-1~Acceptor-3官员,1与2号官员分别收取了10比特币,找到第3号官员时,没想到遭到了3号官员的鄙视,3号官员告诉她,Proposer-2给了11比特币。不过没关系,Proposer-1已经得到了1,2两个官员的认可,形成了多数派(如果没有形成多数派,Proposer-1会去银行提款在来找官员们给每人20比特币,这个过程一直重复每次+10比特币,直到多数派的形成),满意的找老板复命去了,但是此时Proposer-2保镖找到了1,2号官员,分别给了他们11比特币,1,2号官员的态度立刻转变,都说Proposer-2的老板懂事,这下子Proposer-2放心了,搞定了3个官员,找老板复命去了,当然这个过程是第一阶段提交,只是官员们初步接受贿赂而已。故事中的比特币是编号,议题是value。

    这个过程保证了在某一时刻,某一个proposer的议题会形成一个多数派进行初步支持;

 ===============华丽的分割线,第一阶段结束================

  5. 现在进入第二阶段提交,现在proposer-1小姐使用分身术(多线程并发)分了3个自己分别去找3位官员,最先找到了1号官员签合同,遭到了1号官员的鄙视,1号官员告诉他proposer-2先生给了他11比特币,因为上一条规则的性质proposer-1小姐知道proposer-2第一阶段在她之后又形成了多数派(至少有2位官员的赃款被更新了);此时她赶紧去提款准备重新贿赂这3个官员(重新进入第一阶段),每人20比特币。刚给1号官员20比特币, 1号官员很高兴初步接受了议题,还没来得及见到2,3号官员的时候

这时proposer-2先生也使用分身术分别找3位官员(注意这里是proposer-2的第二阶段),被第1号官员拒绝了告诉他收到了20比特币,第2,3号官员顺利签了合同,这时2,3号官员记录client-2老板用了11比特币中标,因为形成了多数派,所以最终接受了Client2老板中标这个议题,对于proposer-2先生已经出色的完成了工作;

这时proposer-1小姐找到了2号官员,官员告诉她合同已经签了,将合同给她看,proposer-1小姐是一个没有什么职业操守的聪明人,觉得跟Client1老板混没什么前途,所以将自己的议题修改为“Client2老板中标”,并且给了2号官员20比特币,这样形成了一个多数派。顺利的再次进入第二阶段。由于此时没有人竞争了,顺利的找3位官员签合同,3位官员看到议题与上次一次的合同是一致的,所以最终接受了,形成了多数派,proposer-1小姐跳槽到Client2老板的公司去了。

===============华丽的分割线,第二阶段结束===============

  Paxos过程结束了,这样,一致性得到了保证,算法运行到最后所有的proposer都投“client2中标”所有的acceptor都接受这个议题,也就是说在最初的第二阶段,议题是先入为主的,谁先占了先机,后面的proposer在第一阶段就会学习到这个议题而修改自己本身的议题,因为这样没职业操守,才能让一致性得到保证,这就是paxos算法的一个过程。原来paxos算法里的角色都是这样的不靠谱,不过没关系,结果靠谱就可以了。该算法就是为了追求结果的一致性。

以两军问题为背景来演绎Basic Paxos

阅读更多

背景

在计算机通信理论中,有一个著名的两军问题(two-army problem),讲述通信的双方通过ACK来达成共识,永远会有一个在途的ACK需要进行确认,因此无法达成共识。

两军问题和Basic Paxos非常相似

  1. 1) 通信的各方需要达成共识;
  2. 2) 通信的各方仅需要达成一个共识;
  3. 3) 假设的前提是信道不稳定,有丢包、延迟或者重放,但消息不会被篡改。

Basic Paxos最早以希腊议会的背景来讲解,但普通人不理解希腊议会的运作模式,因此看Basic Paxos的论文会比较难理解。两军问题的背景大家更熟悉,因此尝试用这个背景来演绎一下Basic Paxos。

为了配合Basic Paxos的多数派概念,把两军改为3军;同时假设了将军和参谋的角色。

假设的3军问题

  1. 1) 1支红军在山谷里扎营,在周围的山坡上驻扎着3支蓝军;
  2. 2) 红军比任意1支蓝军都要强大;如果1支蓝军单独作战,红军胜;如果2支或以上蓝军同时进攻,蓝军胜;
  3. 3) 三支蓝军需要同步他们的进攻时间;但他们惟一的通信媒介是派通信兵步行进入山谷,在那里他们可能被俘虏,从而将信息丢失;或者为了避免被俘虏,可能在山谷停留很长时间;
  4. 4) 每支军队有1个参谋负责提议进攻时间;每支军队也有1个将军批准参谋提出的进攻时间;很明显,1个参谋提出的进攻时间需要获得至少2个将军的批准才有意义;
  5. 5) 问题:是否存在一个协议,能够使得蓝军同步他们的进攻时间?

 

接下来以两个假设的场景来演绎BasicPaxos;参谋和将军需要遵循一些基本的规则

  1. 1) 参谋以两阶段提交(prepare/commit)的方式来发起提议,在prepare阶段需要给出一个编号;
  2. 2) 在prepare阶段产生冲突,将军以编号大小来裁决,编号大的参谋胜出;
  3. 3) 参谋在prepare阶段如果收到了将军返回的已接受进攻时间,在commit阶段必须使用这个返回的进攻时间;

两个参谋先后提议的场景



 

 

  1. 1) 参谋1发起提议,派通信兵带信给3个将军,内容为(编号1);
  2. 2) 3个将军收到参谋1的提议,由于之前还没有保存任何编号,因此把(编号1)保存下来,避免遗忘;同时让通信兵带信回去,内容为(ok);
  3. 3) 参谋1收到至少2个将军的回复,再次派通信兵带信给3个将军,内容为(编号1,进攻时间1);
  4. 4) 3个将军收到参谋1的时间,把(编号1,进攻时间1)保存下来,避免遗忘;同时让通信兵带信回去,内容为(Accepted);
  5. 5) 参谋1收到至少2个将军的(Accepted)内容,确认进攻时间已经被大家接收;

 

  1. 6) 参谋2发起提议,派通信兵带信给3个将军,内容为(编号2);
  2. 7) 3个将军收到参谋2的提议,由于(编号2)比(编号1)大,因此把(编号2)保存下来,避免遗忘;又由于之前已经接受参谋1的提议,因此让通信兵带信回去,内容为(编号1,进攻时间1);
  3. 8) 参谋2收到至少2个将军的回复,由于回复中带来了已接受的参谋1的提议内容,参谋2因此不再提出新的进攻时间,接受参谋1提出的时间;

两个参谋交叉提议的场景



 

  1. 1) 参谋1发起提议,派通信兵带信给3个将军,内容为(编号1);
  2. 2) 3个将军的情况如下
  3. a) 将军1和将军2收到参谋1的提议,将军1和将军2把(编号1)记录下来,如果有其他参谋提出更小的编号,将被拒绝;同时让通信兵带信回去,内容为(ok);
  4. b) 负责通知将军3的通信兵被抓,因此将军3没收到参谋1的提议;

 

  1. 3) 参谋2在同一时间也发起了提议,派通信兵带信给3个将军,内容为(编号2);
  2. 4) 3个将军的情况如下
  3. a) 将军2和将军3收到参谋2的提议,将军2和将军3把(编号2)记录下来,如果有其他参谋提出更小的编号,将被拒绝;同时让通信兵带信回去,内容为(ok);
  4. b) 负责通知将军1的通信兵被抓,因此将军1没收到参谋2的提议;

 

  1. 5) 参谋1收到至少2个将军的回复,再次派通信兵带信给有答复的2个将军,内容为(编号1,进攻时间1);
  2. 6) 2个将军的情况如下
  3. a) 将军1收到了(编号1,进攻时间1),和自己保存的编号相同,因此把(编号1,进攻时间1)保存下来;同时让通信兵带信回去,内容为(Accepted);
  4. b) 将军2收到了(编号1,进攻时间1),由于(编号1)小于已经保存的(编号2),因此让通信兵带信回去,内容为(Rejected,编号2);

 

  1. 7) 参谋2收到至少2个将军的回复,再次派通信兵带信给有答复的2个将军,内容为(编号2,进攻时间2);
  2. 8) 将军2和将军3收到了(编号2,进攻时间2),和自己保存的编号相同,因此把(编号2,进攻时间2)保存下来,同时让通信兵带信回去,内容为(Accepted);
  3. 9) 参谋2收到至少2个将军的(Accepted)内容,确认进攻时间已经被多数派接受;

 

  1. 10) 参谋1只收到了1个将军的(Accepted)内容,同时收到一个(Rejected,编号2);参谋1重新发起提议,派通信兵带信给3个将军,内容为(编号3);
  2. 11) 3个将军的情况如下
  3. a) 将军1收到参谋1的提议,由于(编号3)大于之前保存的(编号1),因此把(编号3)保存下来;由于将军1已经接受参谋1前一次的提议,因此让通信兵带信回去,内容为(编号1,进攻时间1);
  4. b) 将军2收到参谋1的提议,由于(编号3)大于之前保存的(编号2),因此把(编号3)保存下来;由于将军2已经接受参谋2的提议,因此让通信兵带信回去,内容为(编号2,进攻时间2);
  5. c) 负责通知将军3的通信兵被抓,因此将军3没收到参谋1的提议;
  6. 12) 参谋1收到了至少2个将军的回复,比较两个回复的编号大小,选择大编号对应的进攻时间作为最新的提议;参谋1再次派通信兵带信给有答复的2个将军,内容为(编号3,进攻时间2);
  7. 13) 将军1和将军2收到了(编号3,进攻时间2),和自己保存的编号相同,因此保存(编号3,进攻时间2),同时让通信兵带信回去,内容为(Accepted);
  8. 14) 参谋1收到了至少2个将军的(accepted)内容,确认进攻时间已经被多数派接受;

小结

BasicPaxos算法难理解,除了讲故事的背景不熟悉之外,还有以下几点

  1. 1) 参与的各方并不是要针锋相对,拼个你死我活;而是要合作共赢,最终达成一个共识;当大家讲起投票的时候,往往第一反应是要针锋相对,没想到是要合作共赢;很明显可以想到,在第二个场景下,如果参谋1为了逞英雄,强行要提交他提出的进攻时间1,那么最终是无法达成一个共识的;这里的点就在于参谋1违反了规则,相当于产生了拜占庭错误;
  2. 2) 常规的通信协议设计,对于写操作,通常都是只返回成功和失败的状态,不会返回更多的东西;但BasicPaxos的prepare和commit,将军除了返回成功还是失败的状态之外,还会把之前已经发生的一些状态带回给参谋,这个和常规的通信协议是不同的;
  3. 3) 在两军问题的背景下,其实知道进攻时间被至少2个将军接受的是参谋,而不是将军;在“两个参谋交叉提议的场景”下,当参谋1没有做第2次prepare之前,将军1记录的其实是一个错误的进攻时间;理论上来说,任何一个将军在任何一个时刻都无法判断自己不是处在将军1的场景下;因此BasicPaxos在3个蓝军组成的系统中达成了一个共识,但并没有为每个将军明确了共识;
  4. 4) 本文的两个场景都以“两个参谋”来讲,这里的“两个参谋”可能是真的两个不同的参谋,也可能是同一个参谋因为某种原因先后做了多次提议;对应分布式系统的场景

a) 真的有两个并发的client

b) 两个client一先一后;第一个client执行到某个步骤因为某种原因停止了;过了一段时间,另外一个client接着操作同一个数据

c) 同一个client重试;第一次执行到某一步骤因为某种原因停止了,立即或者稍后进行了重试

后记

写这篇文章的时候,参考了以下两篇文章。

 

Paxos算法细节详解(一)--通过现实世界描述算法

http://www.cnblogs.com/endsock/p/3480093.html

 

第一篇文章用了我们喜闻乐见的背景,大部分内容非常容易理解,尤其是用比特币来映射编号,非常贴切;只是对于proposer-1小姐最后的“背叛”会有点违反常识。看完这个故事之后就一直在想更贴切的背景。在两军问题中,蓝军各方是要合作达成一个共识;对于参谋来说,获得了前一个参谋的提议就接受,而不再提出自己的提议是符合逻辑的,这个和paxos也更加吻合。在实际的分布式系统中,如果遇到冲突,涉及的各方也不是要针锋相对争个你死我活,想要的只是能发现冲突,只有一方成功、或者全部失败都无所谓,只要能保证数据一致就行。

以两军问题为背景,在提议编号上找不到合适的映射点,比较生硬,这一点不如第一遍文章中的故事。

 

Question 7: The Two Generals’ Problem of reaching consensus on when to attack is unsolvable, how come it’s possible to have consensus with Paxos?

http://bogdan.pistol.gg/2014/10/20/paxos-algorithm-explained-part-2-insights/#q7

 

paxos最终仍然无法解决两军问题,即使是扩展到3军也是无法解决的。在3军背景下,按paxos算法的定义,最后是达成了一个共同的进攻时间,3军中的任何一方都可以通过paxos算法读取出这个进攻时间。但3军怎么知道在什么时候去读取、其他人是否已经读取,这是一个和两军问题同样的问题;同时由于通信兵可能无限延迟,可能部分蓝军在进攻时间之前读取到了,部分蓝军可能在进攻时间之后才读取到,所以两军最终还是无解的。第二篇参考文章中也详细描述了这些问题。所以写paxos和两军问题,不是说paxos解决了两军问题,只是借用两军问题的背景来演绎paxos。

 

简洁的算法 - PAXOS

 

这是对名为 Paxos 的极其简洁的算法的解释和演示。Paxos 是一系列算法,用于教授一大堆明显不可靠的流程来可靠地做出决定。更正式地说:如果可以满足某些特定条件,它允许一组不可靠的处理器确定性且安全地达成共识,同时确保在无法满足条件时该组保持一致。

下面的演示演示了用 Javascript 实现的 Paxos 实时版本。两个不同的客户端向系统中的随机节点提出新值,并根据联系的节点和顺序,就两个提议值之一达成共识并通知客户端。

PAXOS:我们可以达成一致的事情。

Paxos是一种解决共识问题的算法。Paxos 在现实生活中的真实实现可以在 Cassandra、Google 出色的 Spanner 数据库以及分布式锁定服务 Chubby 等世界级软件的核心中找到。由 Paxos 管理的系统通常是根据它跟踪的值或状态来讨论的。该系统的构建允许许多进程存储和报告该值,即使某些进程失败,这对于构建高可用和强一致的系统非常方便。重申一下,系统的大多数成员必须同意某个特定值实际上是“唯一真实的”值,然后才能如此报告。相反,这意味着一个对世界有过时观念的流氓进程无法报告一些不是“唯一真实”的事情。

让我们为即将到来的解释提供一些定义:

  • Aprocess是系统中的一台计算机。许多人也使用“副本”或“节点”一词来表示此目的。
  • Aclient是一台不是系统成员的计算机,但正在询问系统该值是什么,或者要求系统采用新值。

Paxos只是构建分布式数据库的一小部分:它只实现了将一个新事物写入系统的过程。由 Paxos 实例管理的进程要么会失败,并且不会学到任何东西,要么到最后大多数人都会学到相同的值,从而达成共识。Paxos 并没有真正告诉我们如何使用它来构建数据库或类似的东西,它只是在节点执行决定一个新值的一个实例时管理节点之间的单独通信的过程。因此,就我们这里的目的而言,我们使用 Paxos 构建的是一个数据库,它只能存储一个值,而且只能存储一次,这样在第一次设置后就无法更改它。

读过的胆量

要从基本 Paxos 系统中读取值,客户端会询问系统中的所有进程存储的当前值,然后获取系统中大多数进程保存的值。如果没有多数或没有足够的进程响应,则读取失败。在左侧,您可以看到客户端询问节点它们的值是什么,然后节点将值返回给客户端。当客户端收到大多数同意某个值的响应时,它就已成功读取该值并将其放在手边。

 

与单节点系统相比,这很奇怪。在这两个地方,客户端都需要对系统进行观察来确定状态,但在 MySQL 或一个 memcached 进程等非分布式系统中,软件只需要询问存储该状态的一个规范位置。在简单的 Paxos 中,客户端需要以相同的方式观察状态,但没有规范的存储位置。它需要询问所有成员,以便可以确定实际上只报告了一个值,并且它实际上被大多数节点持有。如果客户端只询问一个节点,它可能会询问一个过时的进程,并得到“错误”的值。进程可能因各种原因而过时:发送给它们的消息可能已被不可靠的网络丢弃,它们可能已失败并以过时的状态恢复,或者算法可能仍在进行中,而进程可能只是没有进行已经收到消息了。值得注意的是,这是“天真的”Paxos:在使用 Paxos 实现系统时,有更好的读取方法,不需要每次读取都联系每个节点,但它们超出了原始 Paxos 算法的范围。

写胆量

让我们检查一下当客户端请求写入新值时,Paxos 使我们的进程集群做什么。以下过程都是为了只写入一个值。最终我们可以使用这个过程作为一个原语,允许多个值被一个接一个地设置,但是基本的 Paxos 算法控制着仅写入一个新值的流程,然后重复该过程以使该东西真正有用。

该过程从 Paxos 管理系统的客户端请求设置新值开始。这里的客户端显示为红色圆圈,进程显示为青色圆圈。Paxos 保证客户端可以将写入请求发送到 Paxos 集群的任何成员,因此对于此处的演示,客户端随机选择其中一个进程。这个属性非常重要而且简洁:它意味着不存在单点故障,这意味着当任何节点由于任何不幸但不可避免的原因发生故障时,我们的 Paxos 治理系统可以继续在线(并且有用) 。如果我们将一个特定节点指定为“提议者”、“主节点”或其他节点,那么如果该节点发生故障,整个系统就会陷入瘫痪。

当收到这个写请求时,接收到写请求的 Paxos 进程会向系统“建议”这个新值。“提案”实际上是 Paxos 中的一个正式思想:对 Paxos 治理的系统提出的提案可能成功也可能失败,并且是确保维持共识的必要步骤。prepare该建议通过从客户端联系的进程到它所知道的所有其他进程的消息的方式发送到整个系统。

序列号

prepare消息在其中保存了所提议的值,以及其中所谓的序列号。序列号由提议进程生成,它声明接收进程应该准备接受具有该序列号的提议。这个序列号是关键:它允许流程区分新旧提案。如果两个进程试图获取一个值集,Paxos 表示最后提出的值应该优先,因此这可以让进程找出哪个是最后一个,从而确定谁在尝试设置最新的值。

这些接收进程能够在系统中进行关键检查:传入prepare消息的序列号是我见过的最高序列号吗?如果是,那么很酷,我可以准备接受这个传入值,并忽略我之前听说过的任何其他值。您可以在右侧的演示中看到这种情况的发生:客户端经常向一个进程提出一个新值,该进程prepare向其他进程发送消息,然后这些进程注意到这些连续较高的序列号胜过旧的序列号,并放弃那些旧的建议。

这个小小的排序想法可以让系统的任何成员发出提案,以避免与上述指定的“提案者”节点相关的单点故障。如果没有这个命令,Paxos 系统的成员将无法确定他们应该准备放心接受哪个提案。

我们可以想象一种不同的共识算法,它没有执行发送第一条消息来要求其他进程确保尝试设置的值是最新的这一步。虽然更简单,但这将不再满足共识算法的安全要求。如果两个进程几乎同时开始提出不同的值(就像下面的演示一样),宇宙可能会密谋反对我们并对齐数据包,以便每个决斗的提议者说服一半的进程接受他们自己的也许是对的也许是错误的值。系统可能会陷入僵局!将会存在两个大小相等的群体,它们呈现不同的价值,这将导致大多数群体不接受任何价值。这种僵局可以通过第一个带有序列号的 Paxos 消息交换来避免,序列号允许进程全部解析它们应该接受哪个提案。使用 Paxos 的序列号,其中一个决斗提案的编号将低于另一个,因此在提案接收过程中将有一种方法明确地选择最新的提案。他们要么先得到较高的数字一,然后收到较低的数字一并拒绝它,要么他们会在一秒钟内获得较高的数字,从而用它替换较低的数字。Paxos 通过利用序列号来控制时间本身来应用时间优先级,从而解决了随着时间的推移达成共识的问题。

 
上面的演示使用的进程只接受最新的消息作为“真相”,而不是使用序列号。由于客户端同时发送,我们最终会出现脑裂,其中某些进程最后收到一条消息,而其他进程收到另一条消息。无法达成共识!
 
上面的演示使用正确的 Paxos 流程,该流程检查传入提案的序列号,以确定是否真正准备好接受新值。所有流程都正确消歧,可以达成共识!

 

旁注:重要的是,任何两个提案者都不能使用相同的序列号,并且它们是可排序的,以便它们真正只引用一个提案,并且可以使用简单的比较来确定提案之间的优先级。在实现 Paxos 时,这些全局唯一且可排序的序列号通常是精确系统时间和集群中节点编号的导数,因此它们会随着时间的推移而增长,并且永远不会相同。

承诺

因此,在提案流程发出提案后,流程会根据他们见过的最高序列号检查提案的序列号,如果是最高的,他们可以承诺不接受任何早于这个新阈值的提案序列号。该承诺作为一条消息返回,从承诺进程发送到提出新值的进程,作为消息promise。这为提议进程提供了计算有多少进程已发送其承诺所需的信息,从而为确定是否已达到多数派提供了基础。如果大多数进程同意接受该提案或更高顺序的提案,则提案进程可以知道它“有发言权”,可以这么说,并且算法可以取得进展。如果出于某种原因,提议者无法从其他进程中提取大部分承诺,则不可能取得进展,因为无法达成共识,因此提议将中止,并通知客户端写入失败。

为了确定提案是否提取了足够的承诺,提案者只需计算他们收到的消息数量promise并与系统中的进程总数进行比较即可。这里“足够”的承诺是指在某个超时之前收到系统中大多数(N/2 + 1)个进程的承诺。最简单的原因可能是系统中超过一半的进程完全失败,因此它们promise永远不会返回消息。这意味着Paxos永远无法获得大多数进程提交的提议值,因此永远无法满足上述读取算法中的多数要求,从而无法达成共识,因此该提议应该被中止。其他会阻止大多数 Promise 被返回的故障模式包括网络分区阻止提议者联系足够的节点,或者更有趣的是,竞争提案已经提取了具有promise更高序列号的 s。

验收

一旦提议者从大多数其他进程中提取了承诺,它就会要求有承诺的进程“接受”他们之前承诺的值。这是算法的“提交”阶段,在此阶段实际取得了进展。如果没有决斗提案、失败或分区,那么该提案将被所有节点接受,Paxos 就完成了!您可以看到,这是右侧的演示,来自提议者的第二轮消息(称为消息)accept导致所有进程都采用(吸入)承诺的值。

然而,对特定进程的接受可能会失败:如果足够多的进程在回复消息后promise但在接收accept消息之前失败,则接受只能发生在少数节点而不是大多数节点上。在这种情况下,Paxos 回合现在处于一种奇怪的状态,其中一些进程已经接受了一个值,但不是全部。这种状态虽然不受欢迎,但由于上面描述的读取逻辑,实际上是“一致的”:尝试从系统读取的客户端必须获得大多数节点对实际值的同意,因此,如果它设法联系所有节点,在节点中,不同的、冲突的值将由不同的少数节点报告。这会导致读取失败,这很糟糕,但 Paxos 一直保持一致,并且不允许在没有达成共识的情况下进行写入。在实际实现中,这种不良状态通常可以通过重复接受阶段以获得更多节点并最终获得多数节点来纠正。

决斗提案

接受也可能因提案的决斗而失败:承诺者回复的承诺是接受具有该提案的序列号或更高序列号的提案的合同。这意味着第二个提案可能会在第一个具有更高序列号的提案之后出现,并从不再接受第一个较早提案的所有流程中提取新的承诺。然而,第一个提议者可能不会发现第二个提议,并继续愉快地使用 Paxos 算法,并发送它的accept消息。收到这些accept消息后,承诺进程将记录比其对第二个提议者的第二个承诺更低的序列号,并简单地拒绝该accept消息。这是正确的:遗憾的是第一个提案尚未取得进展,但在没有达成共识的情况下没有任何价值被接受,并且 Paxos 保持一致。如果客户导致两个不同的流程同时启动提案,则很容易出现这种情况,您可以在上面看到。

如果在某些节点上接受了早期提案第二个提案才出现,那么这里的失败情况会变得更加复杂。这是 Paxos 的危险区域:如果不同的进程接受了不同的值,特别是如果进程组随着时间的推移改变了它们所接受的值,则系统的读取可能会在同一轮 Paxos 的不同时间返回不同的值!这违反了系统只能报告一个值的共识算法安全属性,因此让我们研究一下 Paxos 如何处理连续的提案和接受。

假设第二个提议者从网络分区中恢复,并在第一个提议者已经提出一个值并且该值已经被大多数进程接受后尝试提出一个新值。Paxos 已经“完成”了,因为如果运行读取算法,第一个提议者的值将被报告为系统的值。也就是说,尽管已完成状态,Paxos 仍允许第二个提议者,因为它声明所有阶段均可重复以允许故障纠正。因此,第二个提议者可以运行,但不能改变已接受的值,以保持如上所述的共识。

为了防止这些后来的提案改变接受的值,Paxos 添加了一些技巧来防止提案具有与第一个提案不同的值。如果任何进程已经接受了某个值,Paxos 会强制此后的任何提案也具有相同的已接受值。奇怪的是,但这保持了共识,因为现在在接受开始后,价值永远不会改变。实现的方式是,promise已经接受值的进程返回的消息也携带已经接受的值,并且可以告诉提议者已经接受的旧值。然后,提议者可以检测大多数节点是否已经接受旧值,并更改其提议以匹配该值,或者根本不运行它。在某种程度上,Paxos 在承诺阶段之上搭载了一个读取操作,以确保提案实际上可以自由地改变系统的价值。

数据库

所有这些过程都完成一件事:一次持久写入。Paxos 本身有许多变体,使其速度更快,引入了 master 的思想,牺牲了纯粹的容错能力以提高速度,并且在其之上构建了大量层,将其用作实现实际数据库的原语。关于如何做到这一点的非常有趣的描述可以在下面列出的 Paxos Made Live 论文中找到,但对我们来说,这已经结束了。谢谢阅读!请将任何建议的编辑、更正或反馈发送至harry@harry.me

【转载】两军问题与Paxos算法 & 动画讲解Paxos算法

 

http://harry.me/blog/2014/12/27/neat-algorithms-paxos/

这篇文章里面有用JS写的Paxos过程,有助理解。但是没怎么仔细看,没时间。

 

这篇文章用两军问题来讨论Paxos,也很有意思:

http://iunknown.iteye.com/blog/2246484

在计算机通信理论中,有一个著名的两军问题(two-army problem),讲述通信的双方通过ACK来达成共识,永远会有一个在途的ACK需要进行确认,因此无法达成共识。

(注意:两军问题是无解的。Paxos只是达成共识,涉及ack和行动,仍然是无解)

 

两军问题和Basic Paxos非常相似

1) 通信的各方需要达成共识;

2) 通信的各方仅需要达成一个共识;

3) 假设的前提是信道不稳定,有丢包、延迟或者重放,但消息不会被篡改。

 

为了配合Basic Paxos的多数派概念,把两军改为3军;同时假设了将军和参谋的角色。

假设的3军问题

1) 1支红军在山谷里扎营,在周围的山坡上驻扎着3支蓝军;
2) 红军比任意1支蓝军都要强大;如果1支蓝军单独作战,红军胜;如果2支或以上蓝军同时进攻,蓝军胜;
3) 三支蓝军需要同步他们的进攻时间;但他们惟一的通信媒介是派通信兵步行进入山谷,在那里他们可能被俘虏,从而将信息丢失;或者为了避免被俘虏,
可能在山谷停留很长时间; 4) 每支军队有1个参谋负责提议进攻时间;每支军队也有1个将军批准参谋提出的进攻时间;很明显,1个参谋提出的进攻时间需要获得至少2个将军的批准才有意义; 5) 问题:是否存在一个协议,能够使得蓝军同步他们的进攻时间?

演绎BasicPaxos

1) 参谋以两阶段提交(prepare/commit)的方式来发起提议,在prepare阶段需要给出一个编号;
2) 在prepare阶段产生冲突,将军以编号大小来裁决,编号大的参谋胜出;
3) 参谋在prepare阶段如果收到了将军返回的已接受进攻时间,在commit阶段必须使用这个返回的进攻时间;

两个参谋先后提议的场景

两个参谋交叉提议的场景

小结

BasicPaxos算法难理解,除了讲故事的背景不熟悉之外,还有以下几点:

复制代码
1) 参与的各方并不是要针锋相对,拼个你死我活;而是要合作共赢,最终达成一个共识;当大家讲起投票的时候,往往第一反应是要针锋相对,没想到是要合作共赢;
很明显可以想到,在第二个场景下,如果参谋1为了逞英雄,强行要提交他提出的进攻时间1,那么最终是无法达成一个共识的。
2) 常规的通信协议设计,对于写操作,通常都是只返回成功和失败的状态,不会返回更多的东西;
但BasicPaxos的prepare和commit,将军除了返回成功还是失败的状态之外,还会把之前已经发生的一些状态带回给参谋,这个和常规的通信协议是不同的;
3) 在两军问题的背景下,其实知道进攻时间被至少2个将军接受的是参谋,而不是将军;在“两个参谋交叉提议的场景”下,
当参谋1没有做第2次prepare之前,将军1记录的其实是一个错误的进攻时间;理论上来说,任何一个将军在任何一个时刻都无法判断自己不是处在将军1的场景下;
因此BasicPaxos在3个蓝军组成的系统中达成了一个共识,但并没有为每个将军明确了共识;
4) 本文的两个场景都以“两个参谋”来讲,这里的“两个参谋”可能是真的两个不同的参谋,也可能是同一个参谋因为某种原因先后做了多次提议;
对应分布式系统的场景包括如下:
a) 真的有两个并发的client b) 两个client一先一后;第一个client执行到某个步骤因为某种原因停止了;过了一段时间,另外一个client接着操作同一个数据 c) 同一个client重试;第一次执行到某一步骤因为某种原因停止了,立即或者稍后进行了重试
复制代码

后记

原文也参考了我上面一篇文章参考的文章:

Paxos算法细节详解(一)--通过现实世界描述算法

http://www.cnblogs.com/endsock/p/3480093.html

 

Question: The Two Generals’ Problem of reaching consensus on when to attack is unsolvable, how come it’s possible to have consensus with Paxos?

http://bogdan.pistol.gg/2014/10/20/paxos-algorithm-explained-part-2-insights/#q7

paxos最终仍然无法解决两军问题,即使是扩展到3军也是无法解决的。在3军背景下,按paxos算法的定义,最后是达成了一个共同的进攻时间,3军中的任何一方都可以通过paxos算法读取出这个进攻时间。

但3军怎么知道在什么时候去读取、其他人是否已经读取,这是一个和两军问题同样的问题;同时由于通信兵可能无限延迟,可能部分蓝军在进攻时间之前读取到了,部分蓝军可能在进攻时间之后才读取到,所以两军最终还是无解的。

第二篇参考文章中也详细描述了这些问题。所以写paxos和两军问题,不是说paxos解决了两军问题,只是借用两军问题的背景来演绎paxos。

 

 

 

posted @ 2024-02-22 15:23  CharyGao  阅读(5)  评论(0编辑  收藏  举报