大纲
https://www.zybuluo.com/yulongsun/note/1012707
1. Paxos算法是什么?
Paxos算法是基于消息传递且具有高效容错特性的一致性算法,目前公认的解决分布式一致性问题最有效的算法之一.
Paxos算法基于2PC,并进行了扩展.
2. Paxos算法产生背景
2.1 "拜占庭将军问题"
拜占庭是古代东罗马帝国的首都,由于地域宽广,守卫边境的多个将军(系统中的多个节点)需要通过信使来传递消息,达成某些一致的决定。但由于将军中可能存在叛徒(系统中节点出错),这些叛徒将努力向不同的将军发送不同的消息,试图会干扰一致性的达成。
2.2 Paxos算法由来
故事背景是古希腊 Paxos岛上的多个法官在一个大厅内对一个议案进行表决,如何达成统一的结果。他们之间通过服务人员来传递纸条,但法官可能离开或进入大厅,服务人员可能偷懒去睡觉。
1990 年由 Leslie Lamport 提出的Paxos共识算法,在工程角度实现了一种最大化保障分布式系统一致性(存在极小的概率无法实现一致)的机制。Paxos 被广泛应用在 Chubby、ZooKeeper 这样的系统中,Leslie Lamport 因此获得了 2013 年度图灵奖。
2.3 产生背景
在常见的分布式系统中,总会发生节点宕机或网络异常(包括消息的重复、丢失、延迟、乱序、网络分区)等情况。
Paxos算法主要就是解决如何在一个发生如上故障的分布式系统中,快速正确的在集群内**对某个值达成一致**,并且保证整个系统的一致性。
3. 算法详解
3.1 角色&提案
- [x] 提案(Proposal)
注意:提案的范围>value.后面会讲到,[提案=编号+Value].也可表示为[M,V].
以下描述中暂定:提案=P,Value=V. -
[x] 角色
1、Proposer :Proposer可以提出提案(Proposal).
2、Accecptor: Acceptor可以接受提案.一旦接受提案,提案里面的value值就被选定了.
3、Learner: Acceptor告诉Learner哪个提案被选定了,那么Learner就学习这个被chosen的value.
- 在具体的实现中,一个进程即可能是Proposer,也可能是Acceptor,也可能是Learner.
3.2 问题描述
Paxos算法的核心是一致性。所以将从一致性问题的描述来讲解该算法怎么解决实际问题.
- [x] 对于一个一致性算法的前置条件:
1、在被提出的P中,只有一个V被chosen.
2、如果没有P被提出,就没有V被chosen.
3、在P被选定后,进程都可以学习被chose的P. - [x] 假设不同角色之间可以通过发送消息来进行通信,那么:
1、每个角色以任意的速度执行,可能因出错而停止,也可能会重启。一个value被选定后,所有的角色可能失败然后重启,除非那些失败后重启的角色能记录某些信息,否则等他们重启后无法确定被选定的值。(角色有记录信息的功能)。
2、消息在传递过程中可能出现任意时长的延迟,可能会重复,也可能丢失。但是消息不会被损坏.(即消息内容不会被篡改--拜占庭将军问题)。
3.3 推导过程--(在于理解过程)
3.3.1 只有一个Acceptor
一个Acceptor接受一个P,那么只有一个V被选定。
缺点:如果这个Acceptor宕机,那么整个系统服务不可用。
3.3.2 多Acceptor
- 问题:如何在多Proposer和多Acceptor情况下,选定一个value?
- 讲解步骤分两阶段:约定P1和约定P2.
3.3.2.1 约定P1
P1:一个Acceptor必须接受一个它收到的第一个P.
//我的疑问:接受==被选定?
在此约定在会产生的问题是:如果每个Proposer会产生不同的P,那么多Proposer必定产生多P,发给多个Acceptor。根据约定P1,Acceptor分别接受到P,就会导致不同的V被选定.如下图所示:
上图,P1会产生的问题:v1、v2、v3都没有被选定,因为他们只有被一个Acceptor接受.
对于上述问题,我们需要一个额外的约定:
P1a:一个提案P被选定,需要被半数以上Acceptor接受.
对于P1a,其实就意味着【一个Acceptor必须接受不止一个提案】.
显然,这与P1相矛盾,所以需要重新设计提案。原来的设计是:提案P=value,现在重新设计:提案P=提案编号+value,可表示为[M,V].
新问题:多提案被选定,如何保证被选定的提案P具有相同的value?
3.3.2.2 约定P2
P2: 如果提案P[M0,V0]被选定了,那么所有比M0编号更高的,且[被选定]的P,其value值也是V0.
对于P2中的“被选定”:一个提案要被选定,首先至少要被一个Acceptor批准。因此,可以理解P2为:
P2a:如果提案P[M0,V0]被选定了,那么所有比M0编号更高的,且[被Acceptor批准]的P,其value值也是V0.
只要满足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)矛盾了。
基于以上问题,所有就有了P2b:
P2b:如果P[M0,V0]被选定后,任何Proposer产生的P,其值也是V0.
- 对于P2b中的描述,那么怎样保证:“任何Proposer产生的P,其值也是V0.”呢?
只要满足P2c即可:
P2c:对于任意的M、V,如果[M,V]被提出,那么存在一个半数以上的Acceptor组成的结合S,满足以下两个条件中的任何一个:
① S中没有一个接受过编号小于M的提案。
② S中的Acceptor接受过的最大编号的提案的value为V。
推导完毕.
3.4 算法流程
3.4.1 Propose提出提案
总体思路如下:
1、学习阶段:Prepare请求
Proposer选择一个新的提案P[MN,?]向Acceptor集合S(半数以上)发送请求,要求S中的每一个Acceptor做出如下响应:
1.1 如果Acceptor没有接受过提案,则向Proposer保证:不再接受编号小于N的提案。
1.2 如果Acceptor接受过请求,则向Proposer返回【已经接受过的编号小于N的编号最大的提案】。
2、接受阶段:Acceptor请求
2.1 如果Proposer收到【半数以上】Acceptor响应,则生成编号为N,value为V的提案[MN,V],V为所有响应中编号最大的提案的value.
2.2 如果Proposer收到的响应中没有提案,那么value由Proposer自己生成,生成后将此提案发给S,并期望Acceptor能接受此提案。
3.4.2 Acceptor接受提案
Acceptor可以忽略任何请求(包括Prepare请求和Accept请求)而不用担心破坏算法的安全性。因此,我们这里要讨论的是什么时候Acceptor可以响应一个请求。
我们对Acceptor接受提案给出如下约束:
P1b:一个Acceptor只要尚未响应过任何编号大于N的Prepare请求,那么他就可以接受这个编号为N的提案。
如果Acceptor收到一个编号为N的Prepare请求,在此之前它已经响应过编号大于N的Prepare请求。根据P1b,该Acceptor不可能接受编号为N的提案。因此,该Acceptor可以忽略编号为N的Prepare请求。当然,也可以回复一个error,让Proposer尽早知道自己的提案不会被接受。
因此,一个Acceptor只需记住:1. 已接受的编号最大的提案 2. 已响应的请求的最大编号。
Paxos算法描述
3.4.3 Learner学习提案
Learner学习(获取)被选定的value有如下三种方案:
4. 如何保证Paxos算法的活性
参考:
1、http://www.cnblogs.com/linbingdong/p/6253479.html
2、《从Paxos到ZooKeeper》