Paxos算法深入分析.docx

上传人:b****7 文档编号:8588432 上传时间:2023-01-31 格式:DOCX 页数:12 大小:67.30KB
下载 相关 举报
Paxos算法深入分析.docx_第1页
第1页 / 共12页
Paxos算法深入分析.docx_第2页
第2页 / 共12页
Paxos算法深入分析.docx_第3页
第3页 / 共12页
Paxos算法深入分析.docx_第4页
第4页 / 共12页
Paxos算法深入分析.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

Paxos算法深入分析.docx

《Paxos算法深入分析.docx》由会员分享,可在线阅读,更多相关《Paxos算法深入分析.docx(12页珍藏版)》请在冰豆网上搜索。

Paxos算法深入分析.docx

Paxos算法深入分析

Paxos算法深入分析

夏超伦,盛浩,刘森

 

一算法背景问题分析

1.1Paxos算法处理的问题

Paxos算法解决的问题是一个分布式系统如何就某个值(决议)达成一致[1]。

一个典型的场景是,在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态。

为保证每个节点执行相同的命令序列,需要在每一条指令上执行一个“一致性算法”以保证每个节点看到的指令一致。

一个通用的一致性算法可以应用在许多场景中,是分布式计算中的重要问题。

节点通信存在两种模型:

共享内存(Sharedmemory)和消息传递(Messagespassing)。

Paxos算法就是一种基于消息传递模型的一致性算法。

BigTable使用一个分布式数据锁服务Chubby,而Chubby使用Paxos算法来保证备份的一致性[2]。

1.2不一致性问题的产生

如图1.1所示,一般银行ATM系统的体系结构:

C={c1,c2,…,cn}代表n个客户端(ci一个实例是取款机),S={s1,s2,…,sm}代表m个服务端(si响应每个与之相连的客户端的命令请求;Paxos算法运行的实体)。

图1.1银行ATM结构图

采用这样的体系结构的目的就是保证在若干个服务端出现故障的情况下,所有的客户端仍能不受影响地进行工作。

从而,本文讨论的一致性问题始终是在保证系统可靠性的前提下------因为解决一致性问题最简单而又最不明智的办法就是只设置一个数据处理端(在ATM模型中只存在一个S),这样永远都不会出现不一致的问题。

由于C与S之间的通信是异步的,那么如果c1,c2,c3分别发出如下命令a,b,c,即operation(c1)=a,operation(c2)=b,operation(c3)=c,那么总共可能会产生

=3!

=6种合法命令序列,即(a,b,c),(a,c,b),…,(c,b,a)。

本文不讨论不合法的命令序列,譬如(a,a,c),这在下文会给假设与解释(此外,如果a任务一定要在b之间执行,那么(b,a,c)此类序列也变得不合法。

在本文中假设a,b任务之间是没有顺序制约的,可以想象成a任务为某一个用户在帐户A上进行一个取款操作,b任务为另一个用户在帐户B上进行一个存款操作,由于A,B是两个不相同的帐户,所以a任务的执行与b任务的执行不相关)。

如果S中的每一个服务端执行了不同的合法命令序列,将会导致整个系统的不一致性问题,所以Paxos的任务是保证S中每一个处于正常工作的服务端都将执行一个相同的命令序列,例如(a,b,c)。

1.3算法的一些前提

前提1:

为了保证不出现一些不合法的命令序列,首先Paxos算法执行的环境应当处在一个可靠的通信环境中。

即在异步通信过程中,发送的数据可能会被丢失(lost)、延长(delayed)、重复(duplicated)[4],但不会出现被篡改。

前提2:

任意一个算法运行的实体(例如ATM系统中的S)不会出现拜占庭将军问题(Byzantinefailure)[5],可以简单地理解为结点群在决定命令序列的过程中没有结点受病毒、黑客影响。

二算法介绍与分析

2.1算法详细描述

2.1.1角色分类

便于理解,在这里把一个结点的所有行为概括成3种角色:

Proposer,Acceptor,Learner。

可以认为在一个结点中Paxos算法的行为可以被独立地分成3种对象来执行,对象之间的交互是统一的。

其中:

Proposer向Acceptor提交提案(proposal),提案中含有决议(value)。

Acceptor审批提案。

Learner执行通过审批的提案中含有的决议。

2.1.2核心思想

一个Paxos算法执行的实例中只确定一个决议。

我们使用数学归纳法的思想来保证如何只确定一个决议被批准:

一个决议(value)被“批准”,当且仅当含有该决议的提案(proposal)被大多数(majority)的Acceptors所“接受”

某个决议v被批准后,接下来(a)没有任何提案被接受;或者(b)只有包含决议v的提案被接受。

其中:

提案(proposal):

一个有序对<编号,决议>

决议(value):

一个整数

提案被接受:

某一个Acceptor向该提案的Proposer发出Accepted信息,并将该提案包含的value加入自己的V_A(list)

决议被批准:

含有该决议的提案被Acceptors集合中的任意一个Majority的所有成员接受

Majority:

,例如S=(A,B,C,D,E),其中(A,B,C),(A,C,D)都是majority,而(A,B)不是;通过反证法可以证明S的任意两个majority的交都不为空,即不会存在两个提案被两个完全不同的majority各自批准的非法场景。

,假设

,即

那么

由于

,必然有

,得

,与假设矛盾,故前提假设不成立。

2.1.3Proposer行为分析

(1.1)向所有的Acceptors发送Prepare(N_A)请求;

(1.2)如果收到Reject(N_H)信息,那么重新发送Prepare(N_H+1);

(2.1)如果收到Acceptors集合的任意一个Majority的Promise(N_A,V_A)回复,那么如果所有的V_A均为空,Proposer自由选取一个V_A’,回发Accept(N_A,V_A’);否则回发Accept(N_A,V_i);

(2.2)如果收到Nack(N_H),回到(1.1)过程,发送Prepare(N_H+1);

(3.1)如果收到任意一个Majority所有成员的Accepted信息(表明选举完成),向所有Proposers发送自身成为leader的消息;

(3.2)向Learner发送value值。

其中:

N_A为该次提案的编号;

N_H为当前提案的最高编号;

V_i为V_A中提案编号最高的value;

2.1.4Acceptor行为描述

(1.1)接收Prepare(N_A),如果N_A>N_H,那么回复Promise(N_A,V_A),并置N_H=N_A;否则回复Reject(N_H)

(2.1)接收Accept(N_A,V_A),如果N_A

其中:

Promise(N_A,V_A):

向Proposer保证不再接受编号不大于N_H的提案;

Accepted向Proposer发送决议被通过信息;

V_A为Acceptor之前审批过的决议(允许为空);

N_H为Acceptor之前接收提案的最高编号。

2.1.5Learner行为描述

相对来说,Learner的行为理解更简单一些:

学习value,开始执行任务。

2.1.6整体描述

算法在执行过程中,实例和实例之间是异步的;角色和角色之间既有同步的行为(因为一个完全异步的系统中,一致性问题将是无法被解决的[6]),又有异步的行为。

下表2.1中按照我的理解以全局的角度来说明这其中的关系:

表2.1一次Paxos实例

角色/时段

Phase1

Phase2

Phase3

Proposer(P)

[1]竞争Leader:

向A发送prepare

[1]接收A的promise

[2]选取一个value并发送accept

(*)

Acceptor(A)

[1]接收处理P的prepare

[2]回复reject或promise

[1]接收处理accept

[2]回复accepted或nack

[3]通知L

(*)

Learner(L)

[1]接收广播学习value或

[2]创建Proposer对象学习value

2.1.7算法总结

该算法巧妙之处在于利用了Majority机制保证了2F+1的容错能力,即具备2F+1个结点的系统最多允许F个结点同时出现故障,并且通过数学归纳的思想步步保障Majority机制。

并且从概率上展示了出现错误(无限循环竞争)的极小可能性。

2.2算法伪代码描述

这个代码换了一种角度来理解本算法,更详细的代码请见[3]。

PaxosPhase1

//proposer状态

anode(maybemorethanone...)decidestobeleader(neednotbeincurrentview):

//静态实现proposal编号唯一性

my_n=max(n_h,my_n)+1,appendnodeID

done=fals

//向所有acceptor发送提案proposal

sendsprepare(vid_h+1,my_n)toallnodesin{views[vid_h],initialcontactnode,itself}

//切换到acceptor状态

ifnodereceivesprepare(vid,n):

//如果收到的是以前的实例(譬如说一个结点刚从故障中恢复,它从日志中获得它出现故障前最近的那个任务,但它并不知道该任务已经由集群中的其他结点集完成)

ifvid<=vid_h:

returnoldview(vid,views[vid])

//如果是新的任务

elseifn>n_h:

n_h=n

done=false

//n_a过去接受的proposer的编号,如果以前都没有接受过,那么n_a=v_a=0

returnprepareres(n_a,v_a)

else:

//拒绝

returnreject()

PaxosPhase2

//proposer角色

//获得信息:

该任务已经过时

ifleadergetsoldview(vid,v):

views[vid]=v

vid_h=vid

//转如下一个paxos实例

viewchange

restartpaxos

elseifleadergetsreject():

//被拒绝,延迟,重复本实例,暗示着leader还没确定

delayandrestartpaxos

//从大多数的Acceptor获得回应

elseifleadergetsprepareresfrommajorityofnodesinviews[vid_h]:

//判断是否已经有value被确定,相当重要

ifanyprepareres(n_i,v_i)existssuchthatv_iisnotempty:

//确定value的过程

v=non-emptyvaluev_icorrespondingtohighestn_ireceived

elseleadergetstochooseavalue:

v=setofpingablenodes(includingself)

//回复Accept!

信息

sendaccept(vid_h+1,my_n,v)toallresponders

else:

//准备再次竞争

delayandrestartpaxos

//描述acceptor状态

ifnodegetsaccept(vid,n,v):

//如果是旧的任务

ifvid<=vid_h:

returnoldview(vid,views[vid])

elseifn>=n_h:

//新的任务,保存该任务,回复accepted!

信息,表明一次选举成功

n_a=n

v_a=v

returnacceptres()

else

//选举中间出了问题,说明有编号更大的提案被接受,所以该提案的proposer的accept!

信息应该被否决

returnreject()

PaxosPhase3

//proposer中的leader角色,获得旧的任务信息

ifleadergetsoldview(vid,v):

views[vid]=v

vid_h=vid

viewchange

restartpaxos

//获得最终确认信息,即proposer获知选举结束

elseifleadergetsacceptresfromamajorityofnodesinviews[vid_h]:

//开始广播

senddecide(vid_h+1,v_a)toall(includingself)

else:

delayandrestartpaxos

//learner角色

ifnodegetsdecide(vid,v):

ifvid<=vid_h:

returnoldview(vid,views[vid])

//开始学习

else:

done=true

primaryislowest-numberednodeinv

views[vid]=v

vid_h=vid

viewchange

2.3算法运行实例

这里例举了4个实例。

第一个为结点全部正常的实例;第二个为一个Acceptor出现故障的实例;第三个为一个Proposer成为Leader后发生故障的实例;第四个为两个Proposer进入无限循环竞争的实例。

2.3.1结点全部正常

该实例简单地说明了算法在实际运行中的一般情况:

ClientProposerAcceptorLearner

|||||||

X-------->||||||Request

|X--------->|->|->|||Prepare(N)

||<---------X--X--X||Promise(N,{})

|X--------->|->|->|||Accept!

(N,Vn)

||<---------X--X--X------>|->|Accepted(N,Vn)

|<---------------------------------X--XResponse

|||||||

2.3.2一个Acceptor出现故障

该实例简单地说明了在算法运行过程中一个Acceptor出现故障的实例。

值得注意的,由于一共有2F+1=3(F=1)个Acceptor,所以仅有一个Acceptor出现故障是在故障容忍范围之内的,不会影响算法的完成:

ClientProposerAcceptorLearner

|||||||

X-------->||||||Request

|X--------->|->|->|||Prepare(N)

||||!

||!

!

FAIL!

!

||<---------X--X||Promise(N,{})

|X--------->|->|||Accept!

(N,Vn)

||<---------X--X--------->|->|Accepted(N,Vn)

|<---------------------------------X--XResponse

||||||

2.3.3一个Proposer成为Leader后发生故障

该实例简单地说明了在算法运行过程中一个Proposer成为Leader后发生故障的实例。

由于是Leader出现故障,那么要比一个Acceptor出现故障要复杂得多(但不会影响算法的完成),投票表决过程会被重复,从下图也可以看出:

ClientLeaderAcceptorLearner

|||||||

X----->||||||Request

|X------------>|->|->|||Prepare(N)

||<------------X--X--X||Promise(N,{})

|||||||

|||||||!

!

Leaderfails!

!

|X------------>|||||Accept!

(N,Vn)

|!

|||||

|||||||!

!

NEWLEADER!

!

|X--------->|->|->|||Prepare(N+1)

||<---------X--X--X||Promise(N+1,{Vn})

|X--------->|->|->|||Accept!

(N+1,Vn)

||<---------X--X--X------>|->|Accepted(N+1,Vn)

|<---------------------------------X--XResponse

|||||||

2.3.4两个Proposer进入无限循环竞争

该实例简单地说明了在算法运行过程中一个Proposer发生故障后两个Proposer进入无限循环竞争的实例。

由于该实例由于出现了最坏的情况,算法将永远都不可能完成。

不过该实例的出现的可能性非常小,因为该实例出现无限循环竞争的条件是:

至少存在两个Proposer的Accept!

信息和Prepare信息恰好是按照某种固定顺序相继发送,并且这种顺序永远不能被打乱。

从概率上讲,这在异步通信的环境中是不可能的。

另外,在后面的优化中已经比较详细的介绍了降低出现无限循环竞争情况可能性的优化手段,见3..3。

ClientProposerAcceptorLearner

|||||||

X----->||||||Request

|X------------>|->|->|||Prepare(N)

||<------------X--X--X||Promise(N,{})

|!

|||||!

!

LEADERFAILS

|||||||!

!

NEWLEADER(knowsN)

|X--------->|->|->|||Prepare(N+1)

||<---------X--X--X||Promise(N+1,{})

||||||||!

!

OLDLEADERrecovers

||||||||!

!

OLDLEADERtriesN+1,denied

|X------------>|->|->|||Prepare(N+1)

||<------------X--X--X||Nack(N+1)

||||||||!

!

OLDLEADERtriesN+2

|X------------>|->|->|||Prepare(N+2)

||<------------X--X--X||Promise(N+2,{})

||||||||!

!

NEWLEADERproposes,denied

||X--------->|->|->|||Accept!

(N+1,Vn)

|||<---------X--X--X||Nack(N+2)

||||||||!

!

NEWLEADERtriesN+3

||X--------->|->|->|||Prepare(N+3)

|||<---------X--X--X||Promise(N+3,{})

||||||||!

!

OLDLEADERproposes,denied

|X------------>|->|->|||Accept!

(N+2,Vn)

||<------------X--X--X||Nack(N+3)

||||||||...andsoon...

三算法的思考及优化

3.1体系结构优化

由于分布式系统的体系结构设计引入了一致性问题,并且需要Paxos算法去解决,那么通过对Paxos算法代价的计算可以反过来思考对体系结构的优化。

假设现有函数f(X)用来评价体系结构X的可靠性,函数g(X)来评价体系结构X所带来一致性问题,即X上运行Paxos算法所需要的代价,那么可以定义“增加一台客户端所增加可靠性”函数

其中n为X中结点数量(对应于ATM系统中S的数量)。

同样也可以定义“增加一台客户端所增加一致性问题”函数

那么对

进行比较分析后可以设计出最适合应用场景的体系结构。

这只是个人非常粗浅的想法(见笑)。

3.2Reconfiguration优化

在介绍Paxos算法中提到简单的Paxos算法的容错能力是2F+1。

即在总共有2F+1个服务端的情况,只要不超过F个服务端同时出现损毁,采用Paxos算法的分布式系统都能正常运行。

这种2F+1特性是由算法的核心思路Majority投票机制所决定的,我们目前还没有想到提升允许同时损毁的服务端个数,但是可以通过引入合适的Reconfiguration[5]技术降低整个系统处于无法运行的概率。

因为通过Reconfiguration可以减少F个服务端同时损毁的概率。

而事实上Paxos算法的几个改进版本已经采用了这个方法,例如CheapMulti-Paxos[1]。

3.3算法细节优化

可以对算法中提到的Acceptor,Proposer,Learner三个角色的行为进行优化:

1.Proposer:

在一个Proposer在被告之它的proposal编号不是当前最大的时候,它的行为是立即创建另一个具有更大编号的proposal,并发给所有的Acceptors。

这里可以引入一个随机等待机制,即在一个Proposer的proposal被否决后,它随机等待一定时间然后再创建一个具更大编号的proposal进行竞争。

经过实验证明[5],引入随机等待机制以一定概率降低了出现循环竞争的可能性。

我觉得预先设置一组具有一定规律的数字为等待时间,譬如T={2n,2n+1,2n+2…}会比随机效果更好(这个问题下次再给结论了)。

2.Acceptor:

在一个Acceptor收到更大编号的proposal时,可以向它已经promise过的Proposer提早发出Nack信息,这样会降低通信负载。

因为如果对方在发出Accept信息之前收到Nack信息,那么可以减少一次一定会被拒绝的Accept信息的发送;即便对方已经发送了Accept信息,那么也不会增加任何不必要的通信,因为改Nack信息可以被认为是回复Accept的信息(异步的)。

3.Learner:

在一个proposal被通过后,Learner可以通过创建Proposer角色并向Acceptors发送proposal信息来获得当前最

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 工学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1