Paxos的通俗解释

Paxos的通俗解释

背景

    Paxos是用于一种分布式系统并且具有容错性的一致性算法,是目前业界公认能解决分布式系统一致性的问题算法之一。 Paxos于1990年由Lamport提出,但直到1998才正式被计算机科学界接受。因为Lamport刚开始采用描述故事的方式来描述算法,但不被相关的出版社接受。后来Lamport发表《Paxos Make Simple》论文使得Paxos加速被广大计算机工程师理解并接受。但一直以来计算机的工程师抱怨Paxos算法是难以理解、晦涩,本人在学习之初也有深有体会,所以写下这篇文章总结个人对Paxos算法理解,也供大家参考。

算法核心问题

    Paxos算法的核心问题是:解决分布式系统的一致性的问题,所有问题均围绕着在分布式环境达成一致性而展开讨论的。Paxos算法为了达成一致性,算法就必须保证其安全性和活性。

    安全性:只有被提出的提案才能被选定,并且只有一个提案被选定。

    活性:最终保证会有一个提案被选定。

    安全性和活性的组合结果就是:最终有且只有一个被提出的提案被选定。

角色定义

    在推导算法过程中,我们定义了一些角色及名词。

    proposer:提案者,它可以提出一个提案。

    acceptor:提案的受理者,有权决定是否它本身是否批准该提案。

    choose:提案被选定,当有半数以上Acceptor批准该提案时,就认为该提案被选定了。

    learner:不参与Paxos提案选定的过程,只在提案被选定时,知道提案结果的角色。

    proposal:提案,由Proposer 提出。一个提案由一个编号及value形成的对组成,如[m, value],提案的编号必须是全局唯一,value即代表了提案本身的内容。

    在具体的执行过程中,同一个进程可能不止充当一种角色,同一个进程可能在三个角色中互换。以下是关于这三个角色的通信作以下约定:

    系统所有消息均存在延迟、丢失、重复的可能,系统也可以随时会重启。

    系统所有的消息不存篡改的问题,也即不存在拜占庭的问题。

推导过程

    P1:一个acceptor必须批准(accept)它收到的第一个提案。

    这个需求引出一个问题,就是这个如果有多个提案被不同的proposers同时提出,这可能会导致虽然每个acceptor都批准了一个提案,但是没有一个提案是由多数人都批准的,也就是没有提案可以选定的。

    

    

上图都满足p1需求,但无法选定一个提案。 p1再加上一个提案被选定需要由半数以上的acceptor批准的需求暗示着一个acceptor必须能够批准(accept)不止一个提案。我们为每个提案设定一个编号来记录一个acceptor批准的那些提案。为了避免混淆,需要保证不同的提案具有不同的编号。当一个具有某value值的提案被半数以上的acceptor批准后,我们就认为该value被选定了。此时我们也认为该提案被选定了,提案是由[编号,value]组成。

    P2.如果提案的值为[m,v]被已选定,那所有编号大于m的提案的值必须是v。

因为编号是全序的,条件P2就保证了只有一个Value值被选定的这一关键安全性属性。被选定的提案,首先必须被至少一个Acceptor批准,因此我们可以批准满足如下条件来保证P2。

   P2a. 如果具有value值v的提案被选定了,那么所有比它编号更高的被acceptor批准的提案的value值也必须是v。

    我们仍然需要p1来保证提案会被选定。但是因为系统通信是异步的或者延迟,一个提案可能会在某个acceptor还未收到任何提案时就被选定了。假设一个新的proposer 启动了,然后产生了一个具有另一个value值的更高编号的提案,根据p1,就需要c批准这个提案,但是这与P2a矛盾。因此如果要同时满足p1和P2a,需要对P2a进行强化:

    

    P2b.如果具有value值v的提案被选定,那么所有比它编号更高的被proposer 提出的提案的value值也必须是v。

    一个提案被acceptor批准之前肯定要由某个proposer 提出,因此P2b就隐含了P2a,进而隐含了P2。所以,只要论证P2b成立就可以了。

    假设[M0,V0]值V0的提案被选定了,需要证明任何具有编号Mn(Mn>M0)的提案的Value值为V0。

    为了发现如何保证P2b,我们来如何证明它成立。我们假设某个提案[M0,V0]提案被选定了,需要证明任何具有编号Mn(Mn>M0)的提案值都为V0。也就是我们需要批准数学归纳法证明:假设M0至Mn-1提案的Value值都是V0,证明Mn提案的Value值也是V0因为编号为M0的提案已经被选定了,这意味着肯定存在一个由半数以上的acceptor组成的集合C,C中的每个acceptor都批准了这个提案。再结合归纳假设,M0被选定意味着:

    C中的每个acceptor都批准了一个编号在M0至Mn-1之间的提案,并且每个编号在M0至Mn-1之间的被acceptor批准的提案都具有value值V0。

    任何包含半数以上的acceptor的集合S都至少包含C中的一个成员,我们可以批准维护如下不变性就可以保证编号为Mn的提案value 值为V0:

    P2c.对于任意的Mn和Mv,如果编号为Mn和value值为Mn的提案被提出,那么肯定存在一个由半数以上的acceptor组成的集合S,满足以下二个条件的任意一个:

  • S中不存在任何的acceptor批准过编号小于Mn的提案。
  • 选取S中所有acceptor批准过的编号小于Mn的提案,其中编号最大的那个提案其value为V0。

    只要一直保证P2c的正确性,就可以满足P2b了。从P2开始至P2C,是对提案一系列条件的逐步加强的过程。现在我们只需要证明P2c的正确性就可以了。

    我们再看P2c,实际上P2c规定了每个proposer  如何产生一个提案,对于产生的每个提案[Mn,Mv]需要满足这个条件“存在一个由超过半数的acceptor 组成的集合S:要么S中没有人批准(accept)过编号小于 n 的任何提案,要么S的任何acceptor批准的所有提案(编号小于Mn)中,Mv是编号最大的提案的决议”。当proposer 遵守这个规则产生提案时,就可以保证满足P2b。下面我们反过来看,证明P2c可以保证P2b,采用数学归纳法证明,即是第二数学归纳法。

    首先假设提案[M0,V0]被选定了,设比该提案编号大的提案为[Mn,Vn],我们需要证明的就是在P2c的前提下,对于所有的提案[Mn,Vn],有V0=Vn。

    第一步:当Mn=M0+1时,如果有这样编号的提案,首先我们知道[M0,V0]被选定了,这样就不可能存在一个S且S中acceptor批准过小于Mn的提案[S与批准[M0,V0]的acceptor集合肯定有交集],那Mn只能是多数集S中编号小于Mn的最大编号的那个提案的值了,此时Mn=M0+1,理论上小于Mn的最大的编号肯定是M0,同时由于S和批准[M0,V0]的acceptor集合都是多数集,就保证了二者肯定有交集,这样proposer 在确定Mn取值时,肯定选到就是V0。

    上面实际上就是数学归纳法的第一步,确切的说是使用的是第二数学归纳法证明了第一步。上面是第一步,验证了某个初始值成立。下面,需要假设编号在[M0+1,Mn-1]区间内成立,并在此基础上推出Mn上也成立。

    第二步:根据假设编号在[M0+1,Mn-1]区间内的所有提案value都具为V0,需要证明的是编号为Mn的提案值为V0。根据P2c,首先同样的不可能存在一个S且S中没有人批准过小于Mn的提案,那么编号为Mn的Value值,只能是一个多数集S中编号小于Mn的最大编号的那个提案的值,如果这个最大编号落在[M0+1,Mn-1]区间内的,那么值肯定是V0,如果不是落在[M0+1,Mn-1]区间,那么它的编号肯定就是M0了,不可能比M0再小了,因为S也肯定会与批准[M0,V0]的acceptor集合肯定有交集,那么它的编号值就不会比M0小,而编号如果是M0那么它的值也是V0。由此得证。

    以上这个证明过程使用第二数学归纳法,很多人理解不了Paxos的原理很大部分原因,就是不理解这个证明过程。其实,只要紧扣第P2C中的两个约束条件,多读几遍也就理解了。

    为了维护P2c的不变性,一个proposer 在产生编号为Mn的提案时,必须要知道某一个将要或已经被半数以上acceptor批准的编号小于Mn的最大编号的提案。获取那些已经被批准的提案很简单,只要通过问询就可以实现了。proposer 会请求acceptors不要再批准任何编号小于Mn的提案。这就导致了如下的提案生成算法:

  1. proposer 选择产生一个新的提案编号Mn,然后向某个acceptors集合的成员发送请求,要求aceptor做出如下回应:
    • 保证不再批准任何编号小于Mn的提案。
    • 如果Acceptor已经批准任何提案,就返回向proposer 返回当前acceptor已经批准的但提案编号小于Mn的提案的值value为V。 我们把这样的一个请求称为编号为Mn的prepare请求,这是一个获取数据或读取的过程,也是算法保证安全性非常关键的一步。
  2. 如果proposer 收到了来自半数以上的acceptor的响应结果,那么它就可以产生编号为Mn,value值为V的提案,这里V是所有响应中编号最大的提案的value值,如果响应中不包含任何的提案那么这个值就可以由proposer 任意选择。在确实提案的值后,proposer 批准再向某个acceptors集合发送提案请求,并希望acceptors批准提案,我们称此请求为accept请求。 以上的流程是Paxos的proposer 的提出提案的处理逻辑,也是Paxos难理解、晦涩的方面,也是算法的重点和难点。我个人的学习经历的是P2b和P2c的证明和衔接比较难理解,特别是P2c的数学归纳证明那块逻辑。

    以上的流程是Paxos的proposer 的提出提案的处理逻辑,也是Paxos难理解、晦涩的方面,也是算法的重点和难点。我个人的学习经历的是P2b和P2c的证明和衔接比较难理解,特别是P2c的数学归纳证明那块逻辑。

acceptor批准提案

    从上面的内容可以看到,一个accpetor可能接到二种请求,分别是:prepare和accept请求。我们已经描述了proposer 的算法。那么acceptor端呢?它可以接收两种来自proposer 的请求: prepare请求和accept请求。acceptor可以忽略任何请求而不影响算法的安全性。任何时候acceptor可以回应accept请求,并批准提案,当且仅当它没有承诺或批准一个更高编号的提案。可以推导出加强条件P1a:

    P1A. Acceptor可以批准一个编号为Mn的提案,当且仅当它没有回应过一个编号大于Mn的Prepare请求。

    P1a包含了P1,是P1加强条件。当然,acceptor可以忽略任何prepare和accept请求,也可以延迟和丢失响应,这些均不会影响Paxos的算法的安全性。

    现在我们得到了一个完整的提案选择算法,并满足我们要求的安全属性是基于提案编号上全局唯一的。现在我们做一些简单优化就能得到最终算法:

    假设一个acceptor接收到一个编号为Mn的prepare请求,但是它已经回应了一个编号大于Mn的prepare请求。于是acceptor就没有必要回应这个prepare请求了,因为它不会批准这个编号为Mn的提案。它还可以忽略已经批准过的提案的prepare请求。

    有了这些优化,acceptor只需要保存它已经批准的最高编号的提案(包括编号和决议),以及它已经回应的所有prepare请求的最高编号。因为任何情况下,都需要保证P2C,acceptor必须存储这些信息,包括失效并重启之后。

算法陈述

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

    阶段1.

  1. proposer 选择一个提案编号Mn,向acceptor的多数派发送编号为Mn的prepare请求。
  2. acceptor:如果接收到编号为Mn 的prepare请求,并且Mn大于它已经回应的任何prepare请求,它就返回已经批准的编号最高的提案的value(如果有的话),并承诺不再批准任何编号小于Mn的提案。

    阶段2.

  1. proposer :如果收到了多数acceptor对prepare请求Mn的回应,它就向这些Acceptor发送提案[Mn, Mv]的accept请求,其中Mn是所有prepare请求回应中编号最大的已批准提案的value;或者是proposer 选择的值,如果所有prepare请求的响应均没有带回已批准的提案。
  2. acceptor:如果收到了提案[Mn, Mv]的accept请求,它就批准该提案,除非它已经回应了一个编号大于Mn的提案。

    proposer 可以提出多个提案,只要它遵循上面的算法。它可以在任何时刻放弃一个提案。(这不会破坏正确性,即使在提案被放弃后,提案的请求或者回应消息才到达目标)如果其它的proposer 已经开始提出更高编号的提案,那么最好能放弃当前的提案。因此,如果acceptor忽略一个prepare或者accept请求(因为已经收到了更高编号的prepare请求),它应该告知proposer 放弃提案。这是一个性能优化,而不影响正确性。

活性和选主

    我们很容易构建这样一个场景,两个proposer 持续发送比对方的更高提案编号,并且最终它们两者没有一个被选中。例如:proposer -pn提出 pn1完成了phase 1。另一个proposer  -qn接着批准了qn2 > pn1完成了phase 1。proposer -pn在phase 2的以pn1标记的accept request会被所有acceptor拒绝,因为acceptor已经承诺不接受任何number小于qn2的提案。因此proposer-qn开始用新的pn3 > pn2来开始并完成phase 1,而这又导致了Proposer  qn2在phase 2的accept被忽略。如此反复进行。

    d1c6fd79fa2fe24d8a37dd32d8dcda14849.jpg

    为了保证流程的执行,我们必须选出一个主proposer,作为提案的唯一人选。如果主proposer能和大数派的集合进行通信,并且使用了一个比所有已经批准的提案号都大的编号,那么它就能成功产生被接受的proposal。批准拒绝已有的提案并且批准更高的提案号,主proposer最终会选择到一个足够大的提案号,最终使用提案被选定,从而达到数据一致性的目的。

转载于:https://my.oschina.net/u/3627055/blog/2993589

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值