Paxos算法理解
Posted 数据结构与算法那些事儿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Paxos算法理解相关的知识,希望对你有一定的参考价值。
1. 什么是Paxos算法呢?
2. Paxos的原理是什么呢?
3. Paxos是用来解决什么痛点的呢?
背景
一致性是分布式算法中无法避免的课题。在一个系统中,为了避免数据的丢失,我们会将数据存储到数据库中进行持久化从而解决问题,但是如果出现单点故障的问题后,我们不得不为了保险将数据存储到多台机器上从而提高系统的可用性和可靠性;一旦将数据分布到多个节点上以后,就会出现数据一致性的问题,毕竟在分布式系统中,网络问题,机器故障等等问题都有可能发生。
Paxos算法应运而生,就是用来解决分布式系统中如何就某一个值达成一致(这里的值并不是仅仅是一个数,可以是任何想要保持一致的东西),是目前解决分布式算法最有效的算法之一。
算法概要
Paxos算法是基于消息传递且具有高度容错特性的一致性算法。
在Paxos算法中,主要存在三种角色:
Proposer:负责提案,类似议会中的议员,从人民群众中收集议案;
Aceeptor:负责对提案进行审核,给予通过或者不通过的结果;不会存在单一的情况,通常都是一个整体;类似议会中整个议员群体;
Learner:负责学习提案的结果;
注意
需要注意的是,以上通常不会固定一个角色,而是会同时兼任好几个角色;
算法大概的流程和议会的运行机制比较像,大致如下:
Client向分布式系统发起请求,等待集群系统的响应结果,也就是将提案告知给Proposer;
Proposer收集到提议以后,将提议发送给Acceptor,并尝试让Acceptor接收该提议;
Acceptor针对Proposer呈上的提议进行表决,当超过半数的Acceptor都通过达成共识后,通知结果给Learner;
算法流程
算法流程主要分为两个阶段:prepare阶段和accept阶段,其整体的流程如下:
prepare阶段
Proposer选择一个提案编号N,接着向所有Acceptor发送编号为N的Prepare请求,称为
Prepare(N)
;Acceptor在接收到编号为N的请求后,由于Acceptor只会接收编号比本地维护的最大编号要大的,所以会先检查是否大于本地维护的最大编号;如果小于等于的话,则返回error或者不做回应;如果大于的话,则会把本地维护的最大编号发送回Proposer(如果之前还没有accept提案过的话,则返回
{pok, null, null}
),同时Acceptor更新本地维护的最大编号,承诺不再接受任何编号小于该编号的提案,称为Promise(N, {Va, Vb, Vc})
;
accept阶段
如果Proposer收到了半数以上的Acceptor对其发出的编号为N的Prepare请求的响应,那么它就会向对应的Acceptor发送Accept响应,称为
Accept(N, V)
;如果Acceptor收到了针对编号为N的Accept请求,只要Acceptor没有对大于N的Prepare请求做出过响应,那么它就会接受该提案。相反,如果N小于Acceptor本地维护的最大编号,则拒绝回应或者回应error;
PS:上图中Acceptor在接受Accept请求时,对N和ResN进行的比较是错误的,上边的判断应该改为
N>=ResN
,下面的判断应该改为N<ResN
;
注意
可能会存在一种情况:假定有2个proposer先后向acceptor发送请求,acceptor在接收到proposer1的prepare请求后更新编号为proposer1的编号;此时,proposer2接着向acceptor发送比proposer1编号更大的prepare请求,acceptor会立刻更新成proposer2的编号,那么当proposer1发送accept请求时由于编号不满足要求就会被accept给拒绝掉,则重新获取编号再次回到第一阶段发送prepare请求;从此2个proposer之间不断重复发送prepare请求,导致系统出现
活锁
;
思考
在什么情况下可以认为变量的取值被确定,不再更改?
一旦某编号的取值被半数以上的acceptor接受,则认为变量的取值被确定,不再更改;
Paxos的两个阶段分别在做什么?
参考算法流程;
一个编号是否会有多个Proposer进入第二阶段运行?
不会,由于acceptor会维护最大的编号,只会有一个proposer获取访问权,后面小于等于最大编号的proposer是获取不到访问权的;
在什么情况下proposer可以将var的取值确定为自己提交的取值?
当proposer收到超过半数的accept ok响应时,可以将var的取值确定为自己提交的值;
在第二阶段,如果获取的var取值都为空,为什么可以保证旧编号无法形成确定性取值?
由于acceptor会在本地维护确定性取值,只要形成确定性取值时都会进行更新,如果返回空,那就说明没有形成确定性取值;
新编号抢占成功后,旧proposer将如何运行?
旧编号的proposer会重新从acceptor获取到最新的编号,并且对对编号进行递增,重新进入到第一阶段发送prepare请求;
如何保证新编号不会破坏已经达成的确定性取值?
在肯定旧的编号无法形成确定性取值的时候,新的编号才会发送自己的取值,不会冲突,并且一旦旧的编号一旦形成确定性取值,新的编号就肯定可以获取到取值,并且认同该取值,不会进行破坏;
为什么在第二阶段存在变量取值时, 只需考虑已接受编号最大取值f?
说明出现编号存在多个,acceptor也记录着不同的取值,为了保证acceptor最终取值的一致性,让编号低的取值和最大编号的取值保持一致;
最后
Paxos算法严格来讲,是一整个协议族,里面不仅仅包含以上提到的Basic Paxos,还包括Multi-Paxos、Fast Paxos和Egalitarian Paxos等,如果感兴趣的话,后续的文章会再继续讨论;
如果你觉得哪里有误的话,请在下面评论告诉我哦,我会及时改正~
以上是关于Paxos算法理解的主要内容,如果未能解决你的问题,请参考以下文章