这段时间因为工做须要用到zookeeper,因而就看了一下大名鼎鼎的Paxos算法。算法
Paxos算法是分布式经典算法之一,在Leslie Lamport的论文《Paxos made simple》一文中,做者逐步增强最初一致性问题的约束条件,最终得出了一个能够实现的模型。文章中不少东西借鉴大神的博客,在最下面有连接。该文章只是本身加深印象,作个总结。安全
一:基本语义异步
在Paxos算法中有一下几种角色:分布式
Proposer:议案的提议者学习
Acceptor:议案的决议者优化
Client:发出议案者spa
Learner:最终议案的学习者.net
以上四种角色,议案的提议者和决策者最重要,Proposer通俗一点就是Client的使者,Client提出一个议案,而后交于Proposer,Proposer再拿着这个议案去向Acceptor申请。还有一个名词就是最终决议,稍后再介绍。blog
还有一下几种关键字:资源
Proposal:议案,由proposer提出,最终被acceptor批准或者否决
Value:决议,他是议案的内容,一个议案就是一个{编号,决议}对
Accept:批准,表示议案被Acceptor批准
Choose:选择,表示议案被选择,也就是被多数Acceptor批准
算法一致性的基本语义:
1):决议(value)只有在被Proposer提出以后才能被批准成为议案(议案是Proposal)
2):再一次Poaxs算法执行示例中,有且仅有一个value被choosen
3):Learner只能学习最终被批准的value
以上三个语义能够转化为四个约束条件:
P1:一个Acceptor必须接受(accpet)第一次收到的议案
可是该需求可能会致使一个问题,若是多个Proposer分别提出几个不一样的提议,从而致使每一个Acceptor 分 别批注了几个不一样的提议,可是没有一个提议被多数派接受。即便只有两个决议,可是有可能有这种情 况,就是在单个Acceptor失效的状况下,每一个议案都被半数的Acceptor接受,那么仍是没有办法提出最终的议案。
一个决议要通过多数派的批准猜中最终被choose,这个需求和P1暗示了咱们Acceptor必须可以批准多个议案,所以咱们为每一个不一样的议案分配不一样的编号(若是只有三个Proposer,咱们能够给他们编号0,1,2,那么他们的议案编号就能够是3*i+j,其中i能够用来跟踪提出议案的次数,j是他们开始的编号,这样就能够作到惟一递增,同理,多个也是),所以每个议案由编号和决议构成,也就是【议案={编号,决议}】,若是一个议案被多数派Accept,那么他就被choose,咱们容许选择多个议案,可是必须保证全部选择的议案都包括相同的决议,概括以下:
P2. 若是一个议案{n, v}被选择,那么全部被选择的议案(编号更高)包含的决议都是v。
由于编号是全序的,P2保证了“有且仅有一个决议被选择”这一关键属性,议案必须被至少一个Acceptor批准才能被选择,所以只要知足一下条件,就能知足P2:
P2A:一旦一个编号n,value v({n,v})的议案被choose, 那么以后任何Acceptor再次接受的议案(编号更高)必须具备value v
依然根据P1来确认选择了某些议案。由于通讯是异步的,因此可能在有些状况下,某些Acceptor可能没有接受过一些议案,他们可能会错误的批准一个议案,试想一下,加入某个Proposer之内某些缘由down了,可是后续本身又启动了,他提出了一个编号更高的议案,那么根据P21,Acceptor应该去批准这个议案,可是又违背了P2A,因此咱们要去增强P2A:
P2B:一旦一个编号n,value v({n,v})的议案被choose,那么以后任何Proposer提出的议案(编号更高)必须具备value v
由于一个议案只有在被Proposer提出以后才有可能被批准,所以P2B包含了P2A,进而包含了P2
可是如何才能证实P2B,假设某个议案{m,v}被选择,而后咱们能够去证实任何n>m的议案的决议都是v,对n能够简化证实:根据条件,每一个提出的议案(编号m到n-1)他的决议都是v,咱们能够证实编号为n的决议是v,对于选择的议案m,必然存在一个集合c(Acceptor的多数派)中的多数Acceptor已经批准了该议案,综合假设概括,m被选择这一前提意味着:
C中的每一个Acceptor都批准了一个一个编号m到n-1范围内的议案,而且议案的决议都是v
由于任何多数派组成的集合都包括至少C中的一员,那么咱们能够得出结论,若是下面的不变性成立,那么议案n的决议就是v
P2C:对于任意的v和m,若是议案{n,v}被提出,那么存在一个有多数派构成的结合s(或者a,s中没有没有acceptor批准太小于编号n的议案,或者b)在s中的acceptor批准的因此议案(编号小于n)中,v编号小于n的提案的最大决议
经过保持P2C,咱们就能知足P2B,为了保持P2C,准备提出提案(编号为n)的Proposer必须知道全部编号小于n的议案中编号最大的那个,若是存在的话,他可能已经或者将要被Acceptor多数派批准,获取已经批准的议案是简单的,可是预测将要批准的议案确实困难的,Proposer并不预测,它假设不会有这种状况,所以他会硬性规定Acceptor不准批准任何编号小于n的议案,这就引发了下面的基本算法也就是咱们说的两阶段提交。
1):Proposer选择了一个新的编号n,准备向Acceptor集合中全部成员发送请求(Prepare阶段,n是Prepare请求的编号,也是下面accept回应议案的编号),而且要求回应:
a、一个永不批准编号小于n的议案的承诺
b、在他已经批准的编号小于n的议案中,编号最大的议案,若是存在的话,咱们把这样的请求叫作prepare请求n
2):若是Proposer收到多数Acceptor的回应,那么他就能够提出议案{n,v}其中v是全部回应中编号最高的议案的决议,或者是Proposer选择的任意值,前提是Acceptor从未批准过任何议案
一个Proposer发出一个Acceptor集合发送已经被批准的议案,咱们称之为Accept请求
换言之:就是
P1A:Acceptor能够批准一个编号为n的议案,当且仅当他没有回应过一个编号大于n的Prepare请求
P1A包含了P1,如今咱们获得了一个一致性算法,假设知足安全性,假设议案的编号惟一,咱们就能够经过简单的优化,获得下面一致性算法:
假设一个Acceptor接收到一个编号为n的Prepare请求,可是他已经回应了一个编号大于n的Prepare请求,因而Acceptor就没有必要回应这个Prepare请求了,由于他不会这个批准这个编号为n的议案,他还能够忽略已经批准过的议案的Prepare请求。
有了这些优化,Acceptor只须要保存它已经批准过的最高编号的议案(议案的编号和决议),以及他已经回应过得全部Prepare请求的最高编号,由于任何状况下,都须要保证P2C,Acceptor都须要保存这些信息,包括重启以后,注意,Proposer能够随意抛弃一个提案,可是他不会用相同的编号来提出另外一个议案。
其中通讯模型咱们采用异步的非拜占庭模型【拜占庭模型下,消息会丢失,重复,也有可能会损坏,换言之:咱们认为消息可能会丢失,也可能会重复,可是消息不会出现损坏的现象】
下面简单介绍下Paxos算法的一些行为,基本分为两段提交过程:
1)Prepare阶段:
(1):当Proposer但愿提出一个议案V1,首先发送Prepare请求到大多数的Acceptor,Prepare请求的序列号为<SN1>;
(2):当Acceptor接收到编号为<SN1>的Prepare请求的时候,他首先回去检查自身上次回复过得Prepare请求<SN2>
a):若是SN2>SN1,忽略该请求,而且告知提出<SN1>议案的Proposer,他已经回复过一个编号大于SN1的Prepare请求,
b):不然去检查上次批准的Prepare请求<SNx,Vx>,而且回复<SNx,Vx>;若是该Acceptor以前没有回复过,那么直接回复<OK>
2)Accept阶段 :
(1): 由于通信是异步的,因此咱们能够在通过一段时间后,Proposer收到Acceptor的请求,回复能够分为几种:
a):回复的数量知足多数派,并且回复的都是<OK>,那么Proposer发起Accept请求,内容就是<SN1,V1>
b):回复的数量知足多数派,可是有的回复<SN2,V2>,<SN3,V3>.....则,Proposer找到全部回复中超过半数的那个,假如是<SNx,Vx>,则发出Accept请求,内容为<SN1,Vx>,此时他的编号不变,可是议案的决议变成Acceptor回复中超过半数议案的决议Vx
c):回复的数量不知足多数派,那么Proposer会尝试编号+1再次发出Prepare请求,
(2):在不违背本身向其余Proposer的承诺前提下,acceptor收到accpet请求后既接受并回复这个请求。
可是在应用场景下,很容易出现活锁的状况,例如当三个或三个以上的Proposer在发送Prepare请求,很难有一个Proposer收到超过半数的回复而不停的执行第一阶段协议,这就陷入了一个怪圈,所以为了不竞争,加快收敛速度,在算法中引入了一个Leader的角色,在正常状况下有且仅有一个参与者扮演leader角色,除非leader down掉或者是他丢掉了半数之上的Acceptor,才会从新选举leader。并且他角色扮演Acceptor,同时又扮演Learner角色。
在这种优化算法中,只有Leader才能提出议案,从而避免了竞争使得算法快速收敛而趋于一致,此时的Paxos算法在本质上退变为两阶段提交协议。可是在异常状况下,可能出现了多个leader,此时算法有变成了原始的Paxos算法。
Leader的选举也是用到了两阶段提交协议。
此时Leader的工做流程主要分为如下三部分:
一、学习阶段 向其余参与者学习本身不知道的数据(决议)
当一个参与者通过选举后成为了leader,他应该知道绝大多数的Paxos的实例,所以他会立刻启动一个主动学习的过程。假设当前的新Leader早就知道1-134,138和139的Paxos实例,那么他就会执行137-137以及大于139的paxos。若是只检测到135和140的Poxas实例有肯定的值,那他最后就会知道1-135,138-140的paxos的实例。
二、同步阶段 让绝大多数的参与者保持数据(决议)的一致性
此时的Leader已经知道1-134和138-140的poxas实例,那么他会从新执行1-135的实例,以保证绝大多数参与者在1-135的paxos实例上保持一致。对于138-140的实例,他不会立刻去执行,而是等到服务阶段填充了136,137的paxos实例后在执行。这里之因此要填充这些实例,是为了防止之后Leader老是去学习这些间隔的实例,可是这些实例有没有肯定的值,就会形成必定程度的资源浪费。
三、服务阶段 为客户端服务,提议案
Leader将用户的请求转化为Paxos实例,固然,他能够去执行多个Paxos实例,可是若是当前leader出现异常,就有可能出现Paxos实例间断的问题,或者在异常状况下,出现了多个leader,此时Paxos算法就有可能出现活锁的现象。
连接:http://blog.csdn.net/sparkliang/article/details/5740882
连接:http://blog.csdn.net/xhh198781/article/details/10949697
连接:http://shuofenglxy.iteye.com/blog/1188422