分布式系列文章——Paxos算法原理与推导

Paxos算法在分布式领域具有非常重要的地位。但是Paxos算法有两个比较明显的缺点:1.难以理解 2.工程实现更难。

网上有很多讲解Paxos算法的文章,但是质量参差不齐。看了很多关于Paxos的资料后发现,学习Paxos最好的资料是论文《Paxos Made Simple》,其次是中、英文版维基百科对Paxos的介绍。本文试图带大家一步步揭开Paxos神秘的面纱。

Paxos是什么

Paxos算法是基于消息传递且具有高度容错特性一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一。

Google Chubby的作者Mike Burrows说过这个世界上只有一种一致性算法,那就是Paxos,其它的算法都是残次品

虽然Mike Burrows说得有点夸张,但是至少说明了Paxos算法的地位。然而,Paxos算法也因为晦涩难懂而臭名昭著。本文的目的就是带领大家深入浅出理解Paxos算法,不仅理解它的执行流程,还要理解算法的推导过程,作者是怎么一步步想到最终的方案的。只有理解了推导过程,才能深刻掌握该算法的精髓。而且理解推导过程对于我们的思维也是非常有帮助的,可能会给我们带来一些解决问题的思路,对我们有所启发。

问题产生的背景

在常见的分布式系统中,总会发生诸如机器宕机网络异常(包括消息的延迟、丢失、重复、乱序,还有网络分区)等情况。Paxos算法需要解决的问题就是如何在一个可能发生上述异常的分布式系统中,快速且正确地在集群内部对某个数据的值达成一致,并且保证不论发生以上任何异常,都不会破坏整个系统的一致性。

注:这里某个数据的值并不只是狭义上的某个数,它可以是一条日志,也可以是一条命令(command)。。。根据应用场景不同,某个数据的值有不同的含义。


相关概念

在Paxos算法中,有三种角色:

  • Proposer

  • Acceptor

  • Learners

在具体的实现中,一个进程可能同时充当多种角色。比如一个进程可能既是Proposer又是Acceptor又是Learner

还有一个很重要的概念叫提案(Proposal)。最终要达成一致的value就在提案里。

注: - 暂且认为『提案=value』,即提案只包含value。在我们接下来的推导过程中会发现如果提案只包含value,会有问题,于是我们再对提案重新设计。 - 暂且认为『Proposer可以直接提出提案』。在我们接下来的推导过程中会发现如果Proposer直接提出提案会有问题,需要增加一个学习提案的过程。

Proposer可以提出(propose)提案;Acceptor可以接受(accept)提案;如果某个提案被选定(chosen),那么该提案里的value就被选定了。

回到刚刚说的『对某个数据的值达成一致』,指的是Proposer、Acceptor、Learner都认为同一个value被选定(chosen)。那么,Proposer、Acceptor、Learner分别在什么情况下才能认为某个value被选定呢?

  • Proposer:只要Proposer发的提案被Acceptor接受(刚开始先认为只需要一个Acceptor接受即可,在推导过程中会发现需要半数以上的Acceptor同意才行),Proposer就认为该提案里的value被选定了。

  • Acceptor:只要Acceptor接受了某个提案,Acceptor就任务该提案里的value被选定了。

  • Learner:Acceptor告诉Learner哪个value被选定,Learner就认为那个value被选定。


问题描述

假设有一组可以提出(propose)value(value在提案Proposal里)的进程集合。一个一致性算法需要保证提出的这么多value中,只有一个value被选定(chosen)。如果没有value被提出,就不应该有value被选定。如果一个value被选定,那么所有进程都应该能学习(learn)到这个被选定的value。对于一致性算法,安全性(safaty)要求如下:

  • 只有被提出的value才能被选定。

  • 只有一个value被选定,并且

  • 如果某个进程认为某个value被选定了,那么这个value必须是真的被选定的那个。

我们不去精确地定义其活性(liveness)要求。我们的目标是保证最终有一个提出的value被选定。当一个value被选定后,进程最终也能学习到这个value。

Paxos的目标:保证最终有一个value会被选定,当value被选定后,进程最终也能获取到被选定的value。

假设不同角色之间可以通过发送消息来进行通信,那么:

  • 每个角色以任意的速度执行,可能因出错而停止,也可能会重启。一个value被选定后,所有的角色可能失败然后重启,除非那些失败后重启的角色能记录某些信息,否则等他们重启后无法确定被选定的值。

  • 消息在传递过程中可能出现任意时长的延迟,可能会重复,也可能丢失。但是消息不会被损坏,即消息内容不会被篡改(拜占庭将军问题)。

推导过程

最简单的方案——只有一个Acceptor

假设只有一个Acceptor(可以有多个Proposer),只要Acceptor接受它收到的第一个提案,则该提案被选定,该提案里的value就是被选定的value。这样就保证只有一个value会被选定。

但是,如果这个唯一的Acceptor宕机了,那么整个系统就无法工作了!

因此,必须要有多个Acceptor


多个Acceptor

多个Acceptor的情况如下图。那么,如何保证在多个Proposer和多个Acceptor的情况下选定一个value呢?


下面开始寻找解决方案。

如果我们希望即使只有一个Proposer提出了一个value,该value也最终被选定。

那么,就得到下面的约束:

P1:一个Acceptor必须接受它收到的第一个提案。

但是,这又会引出另一个问题:如果每个Proposer分别提出不同的value,发给不同的Acceptor。根据P1,Acceptor分别接受自己收到的value,就导致不同的value被选定。出现了不一致。如下图:


刚刚是因为『一个提案只要被一个Acceptor接受,则该提案的value就被选定了』才导致了出现上面不一致的问题。因此,我们需要加一个规定:

规定:一个提案被选定需要被半数以上的Acceptor接受

这个规定又暗示了:『一个Acceptor必须能够接受不止一个提案!』不然可能导致最终没有value被选定。比如上图的情况。v1、v2、v3都没有被选定,因为它们都只被一个Acceptor的接受。

最开始讲的『提案=value』已经不能满足需求了,于是重新设计提案,给每个提案加上一个提案编号,表示提案被提出的顺序。令『提案=提案编号+value』。

虽然允许多个提案被选定,但必须保证所有被选定的提案都具有相同的value值。否则又会出现不一致。

于是有了下面的约束:

P2:如果某个value为v的提案被选定了,那么每个编号更高的被选定提案的value必须也是v。

一个提案只有被Acceptor接受才可能被选定,因此我们可以把P2约束改写成对Acceptor接受的提案的约束P2a。

P2a:如果某个value为v的提案被选定了,那么每个编号更高的被Acceptor接受的提案的value必须也是v。

只要满足了P2a,就能满足P2。

但是,考虑如下的情况:假设总的有5个Acceptor。Proposer2提出[M1,V1]的提案,Acceptor2~5(半数以上)均接受了该提案,于是对于Acceptor2~5和Proposer2来讲,它们都认为V1被选定。Acceptor1刚刚从宕机状态恢复过来(之前Acceptor1没有收到过任何提案),此时Proposer1向Acceptor1发送了[M2,V2]的提案(V2≠V1且M2>M1),对于Acceptor1来讲,这是它收到的第一个提案。根据P1(一个Acceptor必须接受它收到的第一个提案。),Acceptor1必须接受该提案!同时Acceptor1认为V2被选定。这就出现了两个问题:

  1. Acceptor1认为V2被选定,Acceptor2~5和Proposer2认为V1被选定。出现了不一致。 

  2. V1被选定了,但是编号更高的被Acceptor1接受的提案[M2,V2]的value为V2,且V2≠V1。这就跟P2a(如果某个value为v的提案被选定了,那么每个编号更高的被Acceptor接受的提案的value必须也是v)矛盾了。


所以我们要对P2a约束进行强化!

P2a是对Acceptor接受的提案约束,但其实提案是Proposer提出来的,所有我们可以对Proposer提出的提案进行约束。得到P2b:

P2b:如果某个value为v的提案被选定了,那么之后任何Proposer提出的编号更高的提案的value必须也是v。

由P2b可以推出P2a进而推出P2。

那么,如何确保在某个value为v的提案被选定后,Proposer提出的编号更高的提案的value都是v呢?

只要满足P2c即可:

P2c:对于任意的N和V,如果提案[N, V]被提出,那么存在一个半数以上的Acceptor组成的集合S,满足以下两个条件中的任意一个: - S中每个Acceptor都没有接受过编号小于N的提案。 - S中Acceptor接受过的最大编号的提案的value为V。

Proposer生成提案

为了满足P2b,这里有个比较重要的思想:Proposer生成提案之前,应该先去『学习』已经被选定或者可能被选定的value,然后以该value作为自己提出的提案的value。如果没有value被选定,Proposer才可以自己决定value的值。这样才能达成一致。这个学习的阶段是通过一个『Prepare请求』实现的。

于是我们得到了如下的提案生成算法

  1. Proposer选择一个新的提案编号N,然后向某个Acceptor集合(半数以上)发送请求,要求该集合中的每个Acceptor做出如下响应(response)。 (a) 向Proposer承诺保证不再接受任何编号小于N的提案。 (b) 如果Acceptor已经接受过提案,那么就向Proposer响应已经接受过的编号小于N的最大编号的提案

    我们将该请求称为编号为NPrepare请求

  2. 如果Proposer收到了半数以上的Acceptor的响应,那么它就可以生成编号为N,Value为V的提案[N,V]。这里的V是所有的响应中编号最大的提案的Value。如果所有的响应中都没有提案,那 么此时V就可以由Proposer自己选择。 生成提案后,Proposer将该提案发送给半数以上的Acceptor集合,并期望这些Acceptor能接受该提案。我们称该请求为Accept请求。(注意:此时接受Accept请求的Acceptor集合不一定是之前响应Prepare请求的Acceptor集合)

Acceptor接受提案

Acceptor可以忽略任何请求(包括Prepare请求和Accept请求)而不用担心破坏算法的安全性。因此,我们这里要讨论的是什么时候Acceptor可以响应一个请求。

我们对Acceptor接受提案给出如下约束:

P1a:一个Acceptor只要尚未响应过任何编号大于NPrepare请求,那么他就可以接受这个编号为N的提案

如果Acceptor收到一个编号为N的Prepare请求,在此之前它已经响应过编号大于N的Prepare请求。根据P1a,该Acceptor不可能接受编号为N的提案。因此,该Acceptor可以忽略编号为N的Prepare请求。当然,也可以回复一个error,让Proposer尽早知道自己的提案不会被接受。

因此,一个Acceptor只需记住:1. 已接受的编号最大的提案 2. 已响应的请求的最大编号。


Paxos算法描述

经过上面的推导,我们总结下Paxos算法的流程。

Paxos算法分为两个阶段。具体如下:

  • 阶段一:

    (a) Proposer选择一个提案编号N,然后向半数以上的Acceptor发送编号为N的Prepare请求

    (b) 如果一个Acceptor收到一个编号为N的Prepare请求,且N大于该Acceptor已经响应过的所有Prepare请求的编号,那么它就会将它已经接受过的编号最大的提案(如果有的话)作为响应反馈给Proposer,同时该Acceptor承诺不再接受任何编号小于N的提案

  • 阶段二:

    (a) 如果Proposer收到半数以上Acceptor对其发出的编号为N的Prepare请求的响应,那么它就会发送一个针对[N,V]提案Accept请求半数以上的Acceptor。注意:V就是收到的响应编号最大的提案的value,如果响应中不包含任何提案,那么V就由Proposer自己决定

    (b) 如果Acceptor收到一个针对编号为N的提案的Accept请求,只要该Acceptor没有对编号大于NPrepare请求做出过响应,它就接受该提案


Learner学习被选定的value

Learner学习(获取)被选定的value有如下三种方案:


如何保证Paxos算法的活性


通过选取主Proposer,就可以保证Paxos算法的活性。至此,我们得到一个既能保证安全性,又能保证活性分布式一致性算法——Paxos算法

参考资料

  • 论文《Paxos Made Simple》

  • 论文《The Part-Time Parliament》

  • 英文版维基百科的Paxos

  • 中文版维基百科的Paxos

  • 书籍《从Paxos到ZooKeeper》

相关文章: 

  • 分布式基础通信协议:paxos,totem和gossip


原文地址:http://www.cnblogs.com/linbingdong/p/6253479.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/326513.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java的jdbc驱动server_win7下java用jdbc驱动来连接sql server的方法 (转载)

第一步:下载安装Microsoft SQL Server 2000 Service Pack 4,也就是sql2000的sp4补丁地址如下:第二步:下载jdbc的驱动,解压到任一位置中,下载地址:第三步:就是创建一个java工程,再在w…

浅谈流处理算法 (1) – 蓄水池采样

转载自 浅谈流处理算法 (1) – 蓄水池采样 前言 现如今,“大数据 ”已经不是什么新概念,“一千个人眼中有一千个大数据”。社交网络,智能穿戴设备,智能家居,传感器,机器人等每一个热门的词汇背后都是大量…

2018蓝桥杯省赛---java---B---7(螺旋折线)

题目描述 标题:螺旋折线如图p1.png所示的螺旋折线经过平面上所有整点恰好一次。 对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。 例如dis(0, 1)3, dis(-2, -1)9 给出整点坐标(X, Y),你能计算出dis…

微软的.NET Core开始支持Raspberry Pi 3

微软的 .NET Core 正在向 Raspberry Pi 3 发展,并且适用于 ARM 设备的官方 .NET 2.0 核心将于今年晚些时候发布。微软最近开放了 .NET 核心的编程框架,目前的 ARM32 版本,在 Github 上可用,是多方合作的产物。 一位微软发言人告诉…

轩辕剑之天之痕1-5java_轩辕剑游戏 轩辕剑1到5全系列下载

第 5 页 轩辕剑3外传:天之痕【轩辕剑3外传:天之痕(2000)】本作可以说是轩辕剑最有名气的作品!!!没错,一直以来轩辕剑名声最响亮的一部作品就是《天之痕》,到现在电视剧也终于拍出来了&#xff0…

独占锁、共享锁、更新锁,乐观锁、悲观锁

转载自 独占锁、共享锁、更新锁,乐观锁、悲观锁 1、锁的两种分类方式 (1)从数据库系统的角度来看,锁分为以下三种类型: 独占锁(Exclusive Lock) 独占锁锁定的资源只允许进行锁定操作的…

2019蓝桥杯省赛---java---B---2(不同子串)

题目描述 思路分析 看到不同,想到set去重 截取想到String.substring() 代码实现 package com.atguigu.TEST;import java.util.HashSet; import java.util.Set;class Main{public static void main(String[] args) {String target"0100110001010001";Se…

ASP.NET Core 程序发布到Linux(Centos7)爬坑实战

前言 前阶段弄了个Linux系统想倒腾倒腾.NET Core,结果看了下网上的资料,大部分都是过期的,走了不少弯路,不过还好,今下午总算捣鼓出来了。Linux命令太多了,唉。血的教训:安装一定要看官网的流程。 开始 首先…

关于Unsafe类的一点研究

转载自 关于Unsafe类的一点研究 Unsafe类是java中非常特别的一个类。它名字就叫做“不安全”,提供的操作可以直接读写内存、获得地址偏移值、锁定或释放线程。 通过正常途径是无法获得Unsafe实例的,首先它的构造方法是私有的,然后&#xf…

2019蓝桥杯省赛---java---B---3(数列求值)

题目描述 思路分析 此题类似于斐波那契数列,但是所求20190324项的最后四位数字,要是单纯按照斐波那契数列的思想求下去, 别说long类型,BigInteger类型都存不了这么大的数,然后我们发现,所求20190324项的最…

Visual Studio 2017 ASP.NET Core开发

Visual Studio 2017 ASP.NET Core开发,Visual Studio 2017 已经内置ASP.NET Core 开发工具. 在选择.NET Core 功能安装以后就可以进行ASP.NET Core开发。 新的ASP.NET Core项目为csproj ,打开之前的xproj项目,会提示单向升级,确认以后&#x…

2019蓝桥杯省赛---java---B---4(数的分解)

题目描述 思路分析 方案一&#xff1a;不定顺序&#xff1a;要除以6. 方案二&#xff1a;人为规定&#xff1a;a < b < c 代码实现 方案一 package com.atguigu.TEST;class Main{public static void main(String[] args) {int sum0;for (int i 1; i <1999; i) {f…

最通俗易懂的乐观锁与悲观锁原理及实现

转载自 最通俗易懂的乐观锁与悲观锁原理及实现 一、乐观锁 总是认为不会产生并发问题&#xff0c;每次去取数据的时候总认为不会有其他线程对数据进行修改&#xff0c;因此不会上锁&#xff0c;但是在更新时会判断其他线程在这之前有没有对数据进行修改&#xff0c;一般会使用…

mysql update field_mysql-更新表与另一个选择,但字段是SUM(someField)

基本上我有这样的事情&#xff1a;UPDATETableSETTable.col1 other_table.col1,FROMTableINNER JOINother_tableONTable.id other_table.id问题是我想用如下选择来更新col1&#xff1a;SELECT SUM(col1) FROM other_table WHERE Table.id other_table.id AND period > 20…

分布式一致性算法:Raft 算法

由于微信字数的限制&#xff0c;此处给出的并非全文&#xff0c;请拉到页面最下方点击阅读原文查看完整版。 Raft 算法是可以用来替代 Paxos 算法的分布式一致性算法&#xff0c;而且 raft 算法比 Paxos 算法更易懂且更容易实现。本文对 raft 论文进行翻译&#xff0c;希望能有…

聚集索引、辅助索引、覆盖索引、联合索引

转载自 聚集索引、辅助索引、覆盖索引、联合索引 聚集索引&#xff08;Clustered Index&#xff09; 聚集索引就是按照每张表的主键构造一棵B树&#xff0c;同时叶子节点中存放的即为整张表的行记录数据。 举个例子&#xff0c;直观感受下聚集索引。 创建表t&#xff0c;…

2019蓝桥杯省赛---java---B---6(特别数的和)

题目描述 时间限制: 1.0s 内存限制: 512.0MB 本题总分&#xff1a;15 分【问题描述】小明对数位中含有 2、0、1、9 的数字很感兴趣&#xff08;不包括前导 0&#xff09;&#xff0c;在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40&#xff0c;共 28 个&#xff0c;他…

java谓词_在Java中谓词

我假设你正在谈论来自Guava的com.google.common.base.Predicate 。从API&#xff1a;确定给定input的true值或false值。 例如&#xff0c;一个RegexPredicate可能实现了Predicate &#xff0c;并且对任何匹配给定正则expression式的string返回true。这本质上是一个booleantesti…

.NET Core项目部署到linux(Centos7)

1.开篇说明 a 上篇博客简单的说明了一下 使用.NET Core开发的一个总结&#xff08;.NET Core跨平台&#xff1a;使用.NET Core开发一个初心源商城总括)&#xff0c;那么这篇博客我们就在上一篇博客的基础上对其代码进行部署&#xff0c;将其部署在Linux Centos7下。 b 这周周二…

2020蓝桥杯省赛---java---B---1(指数计算)

题目描述 代码实现 解法一 计算器 解法二 package com.atguigu.lanqiao;import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner input new Scanner(System.in);int a1,b1921,c7;for (int i 0; i < 2020; i) {aa*7;if(a>1…