【zookeeper面试篇】二阶段、三阶段提交协议,Paxos算法
在分布式系统中,每一个机器节点虽然都能够明确地知道自己在进行事务操作过程中的结果是成功或者失败,但是无法直接获取到其他分布式节点的操作结果。因此事务操作需要跨越多个分布式节点时,需要引入一个协调者统一调度所有节点的执行逻辑,被调度的分布式节点被称为参与者。协调者负责调度参与者的行位,并最终决定这些参与者是否要把事务真正进行提交。二阶段提交二阶段提交将一个事务的处理过程分为投票和执行两个阶段,核心是
在分布式系统中,每一个机器节点虽然都能够明确地知道自己在进行事务操作过程中的结果是成功或者失败,但是无法直接获取到其他分布式节点的操作结果。因此事务操作需要跨越多个分布式节点时,需要引入一个协调者统一调度所有节点的执行逻辑,被调度的分布式节点被称为参与者。协调者负责调度参与者的行位,并最终决定这些参与者是否要把事务真正进行提交。
二阶段提交
二阶段提交将一个事务的处理过程分为投票和执行两个阶段,核心是对每个事务都采用先尝试后提交的处理方式
阶段一:提交事务请求
(1)事务询问
- 协调者向所有的参与者发送事务内容。询问是否是可以执行事务提交操作。并开始等待各参与者的响应
(2)执行事务
- 各参与者节点执行事务操作,并将Undo和Redo信息计入事务日志中
(3)各参与者向协调者反馈事务询问的响应
- 如果参与者成功执行了事物操作,那么就反馈给协调者Yes响应,表示事务可以执行
- 反之反馈给协调者No响应,表示事务不可以执行
阶段一只是查看参与者是否可以执行事务,并不是真正执行事务操作
阶段二:执行事务提交
如果所有的参与者都向协调者反馈Yes响应,那么就执行事务提交
执行事务提交
- (1)发送提交请求
- 协调者向所有参与者节点发出Commit请求
- (2)事务提交
- 参与者接收到Commit请求之后,会正式执行事务提交操作,并在完成提交之后释放在整个事务执行期间占用的事务资源
- (3)反馈事务提交结果
- 参与者在完成事务提交之后,向协调者发送Ack消息
- (4)完成事务
- 协调者接收到所有参与者反馈的Ack消息后,完成事务
如果任何一个参与者向协调者返回No响应,或者在等待超时之后,协调者没有接收到所有参与者的反馈响应,那么就会执行中断事务
中断事务
- (1)发送回滚请求
- 协调者向所有参与者节点发出Rollback请求
- (2)事务回滚
- 参与者收到Rollback请求后,会利用其在阶段一中记录的Undo信息来执行事务回滚操作
- 在完成回滚之后释放在整个事务执行期间占用的资源
- (3)反馈事务回滚结果
- 参与者在完成事务回滚之后,向协调者发送Ack消息
- (4)中断事务
- 协调者接收到所有参与者反馈的Ack消息后,完成事务中断
简单点来说,二阶段提交分为以下两步
第一阶段:提交事务请求
- 协调者向所有参与者发送事务的内容,然后询问是否可以执行事务提交操作。并且等待参与者的响应。
- 参与者执行事务操作,之后会向协调者返回是否成功执行了事务的操作
第二阶段:执行事务提交
- 协调者根据参与者的反馈情况来判断是否可以进行事务的提交操作
二阶段提交的优点
- 原理简单,实现方便
二阶段提交的缺点
- 同步阻塞、单点问题、脑裂、太过保守
同步阻塞
- 指协调者要等所有的参与者反馈yes响应之后才会进行发送提交请求
- 那么比如现在有三个参与者,两个已经反馈了yes,而第三个没有还没有反馈yes,此时就要一直等到第三个反馈完yes之后协调者才会发送提交请求
单点问题
- 因为只有一个协调者,当这个协调者宕掉的话,就会出现问题
数据不一致(脑裂)
- 在协调者向所有参与者发送Commit请求时,可能只发送到一部分的参与者那里,只有一部分参与者收到了Commit请求,那么这种情况下,收到Commit请求的参与者执行事务提交,没收到的则没执行,因此出现了数据不一致
太过保守
- 任意一个节点出现问题都会导致整个事务失败
三阶段提交
三阶段提交是在二阶段提交的基础上,将二阶段提交中的“提交事务请求”过程一分为二,协调者先询问参与者是否可以执行事务提交,如果参与者都响应yes,再进行预提交操作,将预提交操作结果反馈给协调者,协调者根据反馈过来的结果选择进行提交事务或者中止事务,解决了二阶段提交中的无限期等待问题
阶段一:CanCommit
- (1)事务询问
- 协调者向所有的参与者发送一个包含事务内容的canCommit请求,询问是否可以执行事务提交操作,并开始等待各参与者的响应
- (2)各参与者向协调者反馈事务询问的响应
- 参与者在接收到来自协调者的canCommit请求后,正常情况下,如果其自身认为可以顺利执行事务,那么会反馈Yes响应,并进入预备状态,否则反馈No响应
阶段二:PreCommit
协调者根据参与者反馈情况决定是否可以进行事务的PreCommit操作
执行事务预提交
如果参与者反馈的都是yes,那么就会执行事务预提交
- (1)发送预提交请求
- 协调者向所有参与者节点发出preCommit的请求,并进入PrePared阶段
- (2)事务预提交
- 参与者收到preCommit请求后,会执行事务操作,并将Undo和Redo信息记录到事务日志中
- (3)各参与者向协调者反馈事务执行响应
- 如果参与者成功执行了事物操作,就会反馈给协调者Ack响应,同时等待最终的指令:提交(Commit)或中止(abort)
中断事务
如果任何一个参与者向协调者返回No响应,或者在等待超时之后,协调者没有接收到所有参与者的反馈响应,那么就会执行中断事务
- (1)发送中断请求
- 协调者向所有参与者节点发出中止请求
- (2)中断事务
- 不管是收到协调者的中止请求,或者是在等待协调者请求过程中出现超时,参与者都会中断事务
阶段三:doCommit
这个阶段才会真正提交事务
执行提交
如果协调者处于正常工作状态,并且收到所有参与者的Ack响应
- (1)发送提交请求
- 协调者从“预提交”状态转换到“提交”状态,并向所有的参与者发送doCommit请求
- (2)事务提交
- 参与者收到doCommit请求后,会正式执行事务提交操作
- 并在完成提交之后释放在整个事务执行期间占用的事务资源
- (3)反馈事务提交结果
- 参与者完成事务提交之后,向协调者发送Ack消息
- (4)完成事务
- 协调者接收到所有参与者反馈的Ack消息后,完成事务提交
中断事务
如果任何一个参与者向协调者返回No响应,或者在等待超时之后,协调者没有接收到所有参与者的反馈响应,那么就会执行中断事务
- (1)发送中断请求
- 协调者向所有参与者节点发送中止(abort)请求
- (2)事务回滚
- 参与者收到abort请求后,会利用其在阶段二中记录的Undo信息来执行事务回滚操作
- 在完成回滚之后释放在整个事务执行期间占用的资源
- (3)反馈事务回滚结果
- 参与者在完成事务回滚之后,向协调者发送Ack消息
- (4)中断事务
- 协调者接收到所有参与者反馈的Ack消息后,中断事务
阶段三中存在的问题
如果协调者出现问题或者和参与者之间的网络出现故障,都会导致参与者无法及时接收到来自协调者的doCommit或是abort请求。对于这种情况,参与者都会在等待超时之后,继续进行事务提交
三阶段提交的优缺点
优点
- 三阶段提交降低了参与者的阻塞范围
- 如果有参与者出现问题,那么在阶段一就能反馈给协调者,而阶段一还没有进行事务的提交操作
- 并且在出现单点故障后继续达成一致
- 如果协调者出现问题,参与者在等待超时之后会继续进行事务提交
缺点
- 参与者接收到preCommit消息后,如果网络出现分区,此时协调者所在的节点和参与者无法进行正常的网络通信,那么该参与者依然会进行事务的提交(如果协调者出现问题,参与者在等待超时之后会继续进行事务提交),导致数据不一致
Paxos算法
拜占庭将军问题
拜占庭帝国有许多支军队,不同军队的将军之间必须制订一个统一的行动计划,从而做出进攻或者撒退的决定,同时,各个将军在地理上都是被分隔开来的,只能依靠军队的通讯员来进行通讯。然而,在所有的通讯员中可能会存在叛徒,这些叛徒可以任意篡改消息,从而达到欺骗将军的目的
问题
假设有一组可以提出提案的进程集合,对于致性的算法需要满足:
- 被提出的提案中只能有一个提案产生
- 假设个提案被选定后,进程可以获取被选定的提案信息
Paxos算法是一种基于消息传递的且具有高容错性的一种算法,解决的问题是一个可能发生宕机或者网络异常的分布式系统如何就某个值(决议)达成一致。该算法前提是假设不存在拜占庭将军问题。
Paxos算法中有三个角色,分别是Proposer,Acceptor和Learner
-
Proposer负责提出提案
-
acceptor负责对提案做出裁决
-
learner负责学习得到的答案
为了避免单点故障,会有一个acceptor集合,proposer向该集合发送提案,acceptor集合中的每个成员都有可能同意该提案并且每个acceptor只能批准一个提案,当有一半以上的成员同意,则同意该提案
Paxos算法主要分为两个阶段
- prepare阶段
- accept阶段
Prepare阶段(提案生成)
-
proposer提出编号为Mn的提案,向acceptor集合发送prepare请求
-
Acceptot做出反馈:保证不会再接受任何编号比Mn小的提案。如果acceptor已经批准过某个提案,会向proposer返回已经批准的提案中,编号最大的提案的value值
-
如果acceptor收到一个编号为Mn的请求且编号大于acceptor已经响应的所有prepare请求的编号,那么它会将自己已经批准过的编号最大的提案值反馈给proposer,同时acceptor承诺不会再接受编号比Mn小的提案(优化,忽略编号小于已批准的提案的请求)
-
如果proposer收到了acceptor集合半数以上的响应,则会发出一个针对[Mn,Vn]的accept请求给acceptor集合。Vn为收到的所有响应中编号最大的提案的值。如果响应不包含值,则可以由proposer选择任意值
Accept阶段(批准提案)
- acceptor收到accept请求后,只要未收到任何编号大于Mn的prepare请求,则通过该提案(Accept阶段接受提案的请求)
learner学习被选定的value(有三种方案)
方案1
- Acceptor接受了一个提案,就将该提案发送给所有Learner
- 优点
- Learner能快速获取被选定的value
- 缺点
- 由于需要让每个Acceptor与所有learner逐个进行一次通信,通信次数至少为二者个数乘积(M*N)
方案2
- Acceptor接受了一个提案,就将该提案发送给主Learner,主Learner再通知其他的Learner
- 优点
- 大大减少了通信次数,(M+N-1)
- 缺点
- 单点问题,主Learner可能出现故障
方案3
- Acceptor接受了一个提案,就将该提案发送给一个Learner集合,Learner集合再通知其他Learner
- 优点
- Learner集合中的Learner个数越多,可靠性就越好
- 缺点
- 增加了网络通信的复杂度
存在的问题(循环提交):(当Acceptor集合还没有接受任何提案时)
会存在循环提交的问题,导致会称为循环提交体,以至于永远得不到一个确认的提案。
-
比如现在有三个proposer,proposer1,2,3 一个Acceptor集合,此时proposer1发出一个提案编号为M1的提案,Acceptor集合没有接收到任何的提案,所以就会向proposer1反馈,保证接受proposer1提案的值,并且保证不再接受任何比编号M1小的提案,反馈给proposer1的值。
-
而当这个时候,就是说proposer1还没有设定它的值,proposer2又发起了编号为M2的提案给Acceptor集合,而编号M2大于编号M1,所以Acceptor接受proposer2的提案,然后向proposer保证不再接受编号比M2小的提案,之后proposer1把它设定的值反馈给Acceptor集合的时候,由于Acceptor已经向proposer2做出了新的保证,所以不再接受M1,这个时候proposer1把提案的编号改为M3,然后重复刚才的循环过程。会把M2拒绝,M2又生成M4依此类推产生循环
对应优化
为了避免死循环,比如两个proposer一次提出一系列编号递增的提案。可以产生一个主proposer,提案只能由主proposer负责提出
Paxos算法的应用
- chubby(分布式锁服务,GFS中master选举)
总结
Paxos算法引入了“过半”概念,同时支持分布式节点角色之间的轮换,大大避免了分布式单点的出现,即解决了无限期等待问题,也解决了数据不一致问题。
更多推荐
所有评论(0)