介绍

Paxos算法是一个高容错性的分布式一致性算法。去年学习过Paxos算法,一直没将整理到博客。现在将经典Paxos算法相关内容整理到博客上。

经典Paxos算法本身也并不是太难理解,Lamport从期望的结果出发,通过增强条件一步步反推,最终发掘出可以保证了系统一致性的Paxos算法。如果能仔细体会到这其中一步步的反推,就会觉得Paxos是个很自然的东西了。

首先了解一下Paxos算法的作者Leslie Lamport (个人官网),由于对分布式领域的贡献获得2013年度图灵奖。

这里有一段Lamport获得图灵奖的访谈。他也在TeX基础上发明了LaTeX排版系统

Lamport在1982年与Robert Shostak和Marshall Pease一起发表了The Byzantine Generals Problem,也即著名的拜占庭将军问题。拜占庭将军问题揭示了在异步系统和不可靠通道上达到一致性是不可能的。

在1990年Lamport发表了论文The Part-Time Parliament,这就是Paxos的原始论文,当时没什么人能够懂这篇论文因为其用了讲故事的形式进行算法描述。Lamport拒绝主编要求修改论文的提案,因此论文最终被撤销。

在1997年MIT的Nancy Lynch发布了Paxos原文的修改版Revisiting the Paxos algorithm

这里补充一下,Nancy Lynch曾发表过论文Impossibility of Distributed Consensus with One Faulty Process引出FLP impossibility。

在1998年原论文最终被ACM Transactions on Computer Systems接受。

在2001年Lamport对原文重述,发表了Paxos Made Simple。此版论文简洁易懂,没有复杂数学公式,也成了大多数人学习Paxos的入口。

内容

由于Paxos Made Simple文章本身语言很简洁,本文也尽可能用简洁的表述来呈现Paxos算法。

可以说Paxos算法本身是基于期望的目标/结果的一步步反推并强化条件而得出的。

背景

有一些进程可以发起提案,一致性算法要做到以下几点:

  1. 所有提出的提案中最终只有一个会被选定。
  2. 如果提出任何提案,则就没有被选定的提案。
  3. 如果一个提案被选定,进程应该要能获取到被选定的提案。

对于一致性算法的安全性,需要满足以下3点:

  1. 只有被提出的提案才能被选定。
  2. 只有一个提案能够被选定。
  3. 任何进程认为选定的提案必须是真正被选定的提案。

Pxos算法的目标就是要能够做到以上3点。

这里需要说明什么叫选定:一种很好的判断是否选定的方式是:对提案表决的进程中大多数批准提案。所谓大多数,可以简单理解为超过一半,任意两个大多数的集合一定是有交集的。

角色

定义三种参与者:

Proposer 可以发起提案

Acceptor 可以对Proposer的提案批准/拒绝

Learner 获取最终被选定的提案

这三种角色只是逻辑上的一种区分,在具体实现完全可以一个进程充当多种角色。

推导

假设没有失败/消息丢失,只提出一个提案,也可以选出最终提案,这意味着:

P1: 一个Acceptor必须批准它收到的第一个提案。

满足P1是不够的,因为很可能最终没有提案被大多数Acceptor批准。(这不难想象)

所以P1加上一个提案需要被多数派批准才能选定意味着一个Acceptor必须可以批准不止一个提案,否则很可能产生不出一个被多数派批准的提案。

我们这里可以给每个提案分配一个唯一的自然数作为编号,将提案表示为<id, value>的形式(其中id为编号,value为提案本身),这样可以用来区分每个Acceptor批准的不同提案。于是我们可以说,如果值为某个value的提案被多数派批准后,则该提案被选定。

上面已经将提案的概念演化为由编号与提案表示的一个组合了,这样的话可以有多个<id, value>表示的提案被选定。但必须要保证,所有被选定的提案的value值必须是同一个,否则就违背了一致性算法的初衷了。这里引出:

P2: 如果一个值为v的提案被选定了,则所有被选定的具有更高编号的提案值也必须是v。

P2保证了上文提及的一致性算法的安全性的第2点,即只能有一个提案被选定。因为一个提案要被至少一个Acceptor批准才能能够选定,所以可以通过满足下面引出的P2a来满足P2:

P2a: 如果一个值为v的提案被选定了,则被任一Acceptor批准的具有更高编号的提案值也必须是v。

可以看出,P2a是P2根据一个提案被选定肯定是需要先经过被Acceptor批准出发而得出的强化条件,满足了P2a显然能够满足P2。

这里产生了一个问题,由于通信是异步的,某个Acceptor还没有收到任何提案时,可能系统已经产生了某个被选定的提案,此时这个Acceptor接收到了另一个Proposer发出的具有更高编号的提案,根据P1需要批准,这样的话就与P2a矛盾了。也就是说P2a与P1不兼容

P2a根据提案的被选定的上一步是需要被Acceptor批准出发,强化P2得出P2a。那么这里可以用类似思路,根据一个提案得先被Proposer提出才能被Acceptor批准,进一步强化p2a得出:

P2b: 如果一个值为v的提案被选定了,则之后任一Proposer产生的编号更高的填,value值也必须是v。

P2b可以看作是对Proposer提出提案作出要求,但P2b仍然是很难实现的。下面引出P2c:

P2c: 如果一个提案<n, v>被提出,则必须要存在一个多数Acceptor集S满足如下条件之一:
a) S中任一Acceptor都没有批准过编号小于n的提案。
b) S中Acceptor批准过的编号最大的小于n的提案的值为v。

这其中a)可以看作是初始的边界条件。

只要维持P2c的不变性就可以满足P2b。接下来就通过第二数学归纳法简单证明一下,假定一个提案<n, v>被选定,通过维持P2c可以满足P2b:

假定此时一个Proposer要提出<m, v'>的提案的话:

  1. 当m=n+1时,根据P2c的b),满足存在一个多数Acceptor集S'满足批准过编号最大的小于n的提案值为v'。那么设批准<n, v>的多数Acceptor集为S,则S与S'必然存在交集。对于这些交集Acceptor而言,“批准过的编号最大的小于n的提案”便是<n, v>,则推得v'=v成立。所以在m=n+1时,提出的提案<m, v'> = <n+1, v'> = <n+1, v>。

  2. 假设在编号在[n+1, m-1]的提出的提案的值都为v,需要证明P2b也就是此时v'=v:根据P2c,v'应该等于某个多数Acceptor集S'中Acceptor批准的编号最大的提案的值。

    1). 假设S'中Acceptor批准过编号最大的提案的编号在[n+1, m-1]范围,则根据归纳假设,提案值显然为v。

    2). 假设S'中Acceptor批准过编号最大的提案的编号为n,则此时S'必然与批准<n, v>的那个多数Acceptor集S有交集,而S的所有Acceptor都批准了<n, v>,由此可得提案值为v。

由此得证在满足P2c的条件下,P2b也成立。

算法过程

生成提案

上面P2c中我们可以看出,对于一个要提出提案的Proposer而言,最重要的就是要知道Acceptor已经批准过编号最大的提案是什么。

如果某个Proposer想要提出编号为n的协议,对于Acceptor而言,告诉Proposer它们已经批准过的编号小于n中编号最大的提案是很容易的。但是编号小于n中其余剩下还未被批准的提案(可能是还Acceptor还未收到或者还未响应)后续可能会对结果造成难以预期的影响。Paxos算法中为了避免这种不确定因素,需要Acceptor保证不会再批准任何编号小于n的提案。

这里引出提案生成法:

  1. Proposer选择一个自己的提案编号n,向Acceptor集合(或者一个多数集可)发送Prepare请求,要求Acceptor回应:

    • 承诺保证不再批准任何编号小于n的提案。
    • 如果已经批准了任何提案,告诉Proposer已经批准的最大的小于n的提案值。
  2. 如果Proposer收到了多数派Acceptor响应,则可以根据P2c产生提案。即如果这些Acceptor都没有批准过任何提案,则可以随意选定一个提案值v,否则选择这些响应Acceptor中具有最大编号的提案值。

此时Proposer可以向Acceptor集合(或者一个多数集也可)发送Accept请求请求其批准提案。

批准提案

Acceptor可以在任何时候都可以响应Prepare请求。在不违背已经响应过的承诺的前提下,可以响应Accept请求批准提案。

下面引出对于Acceptor如何对提案的处理逻辑:

P1a: 一个Acceptor批准某个提案当且仅当它没有响应过具有更高编号的Prepare请求。

P1a是对P1的一种强化。

优化

对于Prepare请求,有一个优化点:如果一个Acceptor已经响应了编号为n的Prepare请求,则可以忽略后续任何编号小于n的Prepare请求。因为根据对编号为n的Prepare请求的承诺,Acceptor是不会批准编号小于n的提案,自然没必要响应其Prepare请求了。所以其实对Acceptor而言,只需要维护其响应过的Prepare请求中的最大编号以及批准过的提案中的最大编号即可。一个Proposer只要保证不会产生重复编号的提案,可以随意丢弃提出的提案。

完整的算法描述

综合上述的提交提案与批准提案,下面给出完整的算法描述。

阶段1:

  1. Proposer选择一个提案编号n,向Acceptor的一个多数派集合发送Prepare请求。
  2. Acceptor如果收到编号为n的Prepare请求,如果已经响应过编号大于n的Prepare请求,则可以选择忽略该Prepare请求。否则承诺不会批准编号小于n的提案,并且如果已经有批准过编号小于n的提案的话需要回复给Proposer。

阶段2:

  1. 如果Proposer收到了超过半数的Prepare请求响应,则会根据响应确定提案值,向Acceptor集合(要足以形成多数派,可以不是原先那些)发送Accept请求。
  2. 收到Accept请求的Acceptor只要没有响应过编号更大的Prepare请求,就可以通过提案。

参考资料

The Part-Time Parliament

Paxos Made Simple

《从Paxos到ZooKeeper》

http://www.cs.yale.edu/homes/aspnes/pinewiki/Paxos.html

经典Paxos算法笔记的更多相关文章

  1. Zookeeper笔记(二)Paxos算法与Zookeeper的工作原理

    Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目, 它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理.分布式应用配置项的管 ...

  2. 分布式理论之一:Paxos算法的通俗理解

    维基的简介:Paxos算法是莱斯利·兰伯特(Leslie Lamport,就是 LaTeX 中的"La",此人现在在微软研究院)于1990年提出的一种基于消息传递且具有高度容错特性 ...

  3. 一步一步理解Paxos算法

    一步一步理解Paxos算法 背景 Paxos 算法是Lamport于1990年提出的一种基于消息传递的一致性算法.由于算法难以理解起初并没有引起人们的重视,使Lamport在八年后重新发表到 TOCS ...

  4. Paxos算法小结

    转自不正直的绅士,因百度空间迁移,无法注明出处,我从其google搜索引擎中的cache进行的copy. 不正直的绅士 是跟我一起工作过的非常有才的一个青年才俊. Paxos的使用非常广泛.sanlo ...

  5. 底层算法系列:Paxos算法

    关于算法,面太广.本系列只研究实际应用中遇到的核心算法.了解这些算法和应用,对java码农进阶是很有必要的. 对于Paxos学习论证过程中,证实一句话:有史以来学习paxos最好的地方wiki:Pax ...

  6. 从分布式一致性到共识机制(一)Paxos算法

    从分布式系统的CAP理论出发,关注分布式一致性,以及区块链的共识问题及解决. 区块链首先是一个大规模分布式系统,共识问题本质就是分布式系统的一致性问题,但是又有很大的不同.工程开发中,认为系统中存在故 ...

  7. Paxos 算法 :消息传递一致性

    网络上有很多关于优秀的关于Paxos 算法的文章,我下面进行整理搜集一下: 分布式理论之一:Paxos算法的通俗理解 维基的简介:Paxos算法是莱斯利·兰伯特(Leslie Lamport,就是 L ...

  8. [从Paxos到ZooKeeper][分布式一致性原理与实践]<二>一致性协议[Paxos算法]

    Overview 在<一>有介绍到,一个分布式系统的架构设计,往往会在系统的可用性和数据一致性之间进行反复的权衡,于是产生了一系列的一致性协议. 为解决分布式一致性问题,在长期的探索过程中 ...

  9. 算法笔记(c++)--01背包问题

    算法笔记(c++)--经典01背包问题 算法解释起来太抽象了.也不是很好理解,最好的办法就是一步步写出来. 背包问题的核心在于m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+ ...

随机推荐

  1. Angular2-组件间数据传递的两种方式

    Angular2组件间数据传递有多种方式,其中最常用的有两种,一种是配置元数据(或者标签装饰),一种是用单例模块传递:有两个元数据具有传递数据的功能:inputs和outputs. 一.元数据传递 1 ...

  2. ASP.NET MVC验证码演示(Ver2)

    前一版本<ASP.NET MVC验证码演示>http://www.cnblogs.com/insus/p/3622116.html,Insus.NET还是使用了Generic handle ...

  3. JS DOM操作(五) Window.docunment对象——操作元素

    定位: var a = document.getElementByIt( "id" ) 同辈元素 var b = a.nextSibling;            -- 找 a ...

  4. thinkphp 网址后台典型页面

    知识点: 1.select a提交后 返回选中项 选中项 value是id 但是要显示name b遍历和列举两种形式 <select name="class_id" clas ...

  5. Java并发编程-信号量

    Semaphore 直译是信号量,它的功能比较好理解,就是通过构造函数设定一个数量的许可,然后通过 acquire 方法获得许可,release 方法释放许可.它还有 tryAcquire 和 acq ...

  6. java的锁机制——synchronized

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个线 ...

  7. mysql的密码问题

    常见问题 Access denied for user 'root'@'localhost' (using password: YES) 因密码不对而拒绝访问,再jdbc配置中 常常忽略user和密码 ...

  8. Cookies读写

    /** * Minified by jsDelivr using Terser v3.14.1. * Original file: /npm/js-cookie@2.2.0/src/js.cookie ...

  9. Elasticsearch Query DSL 整理总结(二)—— 要搞懂 Match Query,看这篇就够了

    目录 引言 构建示例 match operator 参数 analyzer lenient 参数 Fuzziness fuzzniess 参数 什么是模糊搜索? Levenshtein Edit Di ...

  10. hadoop学习之yarn资源管理

    一.yarn简介 yarn是在hadoop2.x中才引入的一个新的机制,在hadoop1.x中MapReduce任务需要同时做任务管理和资源分配,那么引入yarn之后,hadoop的资源管理的任务就全 ...