Paper Reading Note:Paxos

特别推荐:两军问题,一篇以实例来讲Paxos流程的好文!

Paxos

The Paxos algorithm, when presented in plain English, is very simple.
简单个屁

目标

在一个分布式系统中,几台计算机要就一个问题达成统一(比如他们要选择一个共同的命令序列)。现在要求在随时可能出现宕机和通讯失败、延迟(但信息不会中途被修改)的情况下设计一种通讯协议,使得他们最终选择出的结果被大多数机器接受

注意:proposal和choose似乎给人一种竞争的关系,但实际上paxos描述的是一种合作关系,即几个机器试图更快的得到共识,不论这个共识由谁提出

概念

  • be chosen:当含有某个value的proposal被多数acceptor接受时,这个value就被确定为最终结果,称该value和对应proposal被选中了
    • 特别的,可以有多个proposal被选中,只要他们都有同一个value

假设

不同的proposal必须具有不同的编号,这个的实现依硬件而异,在本中我们直接假设其成立,并且从小到大按自然数使用

协议

协议规则

为了使得最后必然得出结果,我们要求

  • P1:一个Acceptor必须接受他拿到的第一个proposal

为了只得到一个结果,我们要求

  • P2:如果一个带着v值的proposal被选中了,那么被选中的所有编号高于它的proposal所携带的value值也必须是v

由于是我们在设计这个协议,我们可以通过规定下述条件来简单的实现P2

  • P2a:如果一个带着v值的proposal被选中了,那么被任何acceptor接受的所有编号高于它的proposal所携带的value值也必须是v

假如有一个Acceptor刚刚宕机了,那为了使得它既遵守P1又遵守P2a,我们实际上可以更干脆的要求

扫描二维码关注公众号,回复: 11681981 查看本文章
  • P2b:如果一个带着v值的proposal被选中了,那么被任何proposer提出的所有编号高于它的proposal所携带的value值也必须是v

我们可以看看什么情况下能实现P2b,发现其实可以这样

  • P2c:对于任何一个发布的proposal(n,v),必须存在一个多数Acceptor集合S,要么这个S中的所有Acceptor全部没有v,要么S中的Acceptor所接受的编号最大的proposal的value就是v

P2c可以保证实现所有P2系列的条件,这可以由数学归纳法得到

协议的执行

Proposer

Proposer的议程分两步:prapare request & accept request

  1. 使用一个新的proposal编号n,试图向Acceptor集合的每一个成员(或者至少向大部分)发送请求,并要求其回复如下内容
    • 保证不再接受编号小于n的proposal(直接枪毙已经被prepare但未被接受的proposal,从而避免与之产生冲突)
    • 如果Acceptor当前接受了某个proposal,返回这个proposal(包括编号和值)
  2. 只有一个proposer收到了大部分Acceptor的回应时,它才被允许发布proposal(否则回到步骤1),且它的内容如下
    • 若回应的所有Acceptor当前都没有proposal,那么proposer可以使用任意value进行提议
    • 否则,使用回应的Acceptor所接受的proposal中最高编号最高的proposal对应的value

Acceptor

在proposer议程的基础上,我们必须要更准确的规定Acceptor的行为准则,所以我们需要扩充P1条件

  • P1a:一个Acceptor能够且必须接受一个编号为n的proposal,当且仅当它没有响应过任何一个编号大于n的prepare request
    • 说明:“能够且必须”在原文中的表述为“can”,但根据后文给出的执行过程的描述(it accepts the proposal unless…),这里理解为能够且必须更为贴切,也更方便理解

有了它,这个算法实际上已经完整了,但为了更高效的执行,我们引入如下优化

  • 一个Acceptor在如下情况不会对prepare request进行响应
    • 已经接收到了超过n的prepare request(这个优化除了节约开支,还有一些额外的意义。若不然proposer需要去比较收到的proposal的最大编号和自己手里的编号,或acceptor需要对prepare request回应是否初步接受)
    • 已经接受了编号n的proposal(可能是因为proposer重复发送了信息)

在这个优化下,Acceptor只需要记住当前最新接受的proposal(也即他接受的编号最大的proposal)和它响应过的编号最大的prepare request的编号

完整流程

Prepare Phase

  1. Proposer使用一个proposal的编号n,向全部Acceptor或至少一个majority发送内容为n的prepare request
  2. Acceptor接收一个编号为n的prepare request。若n大于它已经回复的prepare request的编号,那么它将承诺不再接受编号小于n的proposal,并且返回它已经接受的编号最大的proposal

Accepte Phase

  1. 当Proposer收到了大部分Acceptor对它prepare request的回复(否则不提出该proposal),它就给这些回应者发送一个编号为n,值为v的accept request。若回复中存在proposal,v等于其中编号最大的proposal的value;若不然,v任意。
  2. Acceptor接收一个accept request,其中proposal的编号为n,若它没有响应过编号大于n的prepare request,则它立刻接受并返回accepted,若不然,返回rejected

一个proposer可以生成多个proposal,只要它能满足算法要求。它可以在协议的任何时刻放弃proposal。

如果acceptor因为已经接受了更大编号的prepare request而忽略其他的prepare或accept request时,它应通知对应的proposer放弃该proposal。这仅仅是对性能做优化,与正确性无关。

Learner

Learner需要获取被选中的value,可以考虑的策略如下

  • 每个acceptor在接受一个proposal后向所有learner发送这个proposal
    • 尽管这和可以尽快使得learner找到选中的value,但冗余操作实在非常多
  • 选择一个distinguished learner,所有acceptor向它发送proposal,它再把最后选定的value通知其他learner
    • 这个可能不太可靠,因为distinguished learner可能故障
  • 选择一组distinguished learner,任意一个都可以在确定最终结果时通知其他所有learner
    • 中和了以上两者的优缺点

其实因为message可能丢失,所以可能没有learner知道有value被选中了。所以learner可以直接去问acceptor接受了什么proposal。再进一步,可能acceptor的故障使得我们搞不清楚是否有majority接受了一个proposal,这种情况下,learner只有在新的proposal被接受时才知道被选中的value是什么。所以如果一个learner想知道是否有value被选中,以及若有则选中的value是什么,它可以让一个proposer发送一个proposal(使用上文算法)

活锁

两个proposer可能持续发送prepare request导致他们的accept request反复被对方无效化。

为了保证流程的执行,我们必须选出一个distinguished proposer,作为唯一的proposal发送者。

猜你喜欢

转载自blog.csdn.net/Kaiser_syndrom/article/details/105543819