Paxos的通俗解释

Paxos的通俗解释

背景

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

算法核心问题

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

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

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

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

角色定义

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

    proposer:提案者,它能够提出一个提案。学习

    acceptor:提案的受理者,有权决定是否它自己是否批准该提案。优化

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

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

    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被忽略。如此反复进行。

    

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

相关文章
相关标签/搜索