Paxos异常情况总结

本文列举了Paxos算法在各阶段的异常,以及处理流程,异常主要限制在Paxos算法的层面,较少涉及具体工程上的实现(除了个别点提一下),因为实际工程实现需要处理的异常点太多了,部分已经超出了Paxos算法的范畴,本文不做讨论,不足之处欢迎批评指正,共同进步。主要有如下几种异常:

  • Proposer A在Prepare阶段未达成多数派
  • Proposer A在Prepare阶段达成多数派,但发起Accept时未达成多数派
  • 多机Accept阶段连续失败的情况
  • 达成多数派Accept后,有机器执行状态机失败
  • 机器重启后的PaxosLog Replay机制

1.Proposer A在Prepare阶段未达成多数派

A应当直接放弃本次投票请求,并且增加其ProposalId继续发起投票,如果A的ProposalId比B的大,则A可以成功,假设A在发起更大的ProposalId投票前,B已经达成了决议,则A需要放弃此InstanceId上的投票,返回Client失败Retry。
AB之间无限死锁工程上简单的解决策略是:任意随机sleep一小段时间,醒来的时间不一致,因此先醒来的Proposer有机会提前达成决议。

2.Proposer A在Prepare阶段达成多数派,但发起Accept时未达成多数派

例如有ABC三节点的集群,A发起了投票,Prepare阶段得到了B的Promise,AB形成多数派,C未响应,然后A发起了Accept请求,Accept未达成多数派有如下假设场景:

  • 1)AB的Acceptor在执行Accept阶段均失败,没有将value持久化成功,那么不受B3条件约束,value就是失败的,没有达到最后的chosen状态,返回给client失败,新的Proposer会提议新的value。
  • 2)A的Acceptor执行Accept失败,B成功,A在Accept阶段未收到多数派Response,若此时没有任何Proposer开始新的投票,A只需要增大ProposalId再次发起投票进程,C接受此请求没问题,B由于已接受过此accept value,根据B3约束,B需要告知A上一次accept value,和A手里的value实际是相同的,所以没有问题,仍可以返回client成功。
  • 3)A的Acceptor执行Accept失败,B成功,A在Accept阶段未收到多数派Response,若此时C作为Proposer发起了新的投票,在初始阶段因C一直和A失联,其ProposalId是小于AB的,所以C起初的投票会因ProposalId小被拒绝,C只能增大自己的ProposalId,当C的ProposalId大于AB已有的ProposalId时,C就能够获取AB的Promise,但是此场景下,AB任一Acceptor已经Accept过一个value,根据B3约束,C在Prepare阶段能够感知到已被accept的value,因此apply到状态机的value仍是A发起的value,C的value就被忽略了,告知client的结果是VALUE_CONFICT,client应该再次重试。
  • 4)A的Acceptor执行Accept失败(未持久化成功),B Accept成功,但B此时突然core dump,所以A在Accept阶段未收到多数派Response,对于此时的集群ABC,根据B3约束,多数派Accept里才能保证value是chosen的,显然这是未达成多数派Accept的,B已Accept的value是无法保证的,此时的B应该怎么办?B重启后,如果此时恰好没有任何新的提议在B缺失的时间里达成,B的value就和场景1)中假设的相同,此value可再次被chosen,日志“活”了;如果此时已有新的提议已达成,则B已accept的value就“死”了,被新的value取代,满足Paxos B3约束条件的限定,不冲突。

3.多机Accept阶段连续失败的情况

ABC三个节点的集群,A发起了投票,Prepare阶段获得了B的Promise,AB形成多数派,然后A发起了Accept,但只有A accept成功,B未收到Accept消息,此时A恰好core dump,BC之间又开始投票,同样的场景,只有B accept成功,然后B挂掉,集群此时已不可用,C无法达成多数派,那么若AB开始陆续恢复,可以假设有一下场景:

  • 1)A先恢复,AC可以就新的提议达成多数派,但是A已有accept过的value,根据问题2 3)4)中的场景,A的value会“活”;
  • 2)B先恢复,AC可以就新的提议达成多数派,但是B已有accept过的value,根据问题2 3)4)中的场景,B的value会“活”;
  • 3)AB同时恢复,且网络互通,那么如果value肯定是B已accept的value,因为B的ProposalId大。
    所以,B3约束规则再一次发挥效应,对于达到多数派Accept的value,无论如何肯定是此value chosen,未达到多数派Accept的value,value可能是任意值。

4.达成多数派Accept后,有机器执行状态机失败

Proposer A已达成多数派Accept,发起了ProposerSendSuccess,但是状态机Apply执行却失败了,执行失败的机器可以是任意台,假设失败的台数占比:

  • 1)少数派,那么这些机器无法再参与下一轮的投票,必须要等状态机Apply成功才会进入下一轮,其他多数派机器可正常运行;
  • 2)多数派,这些机器无法再参与下一轮的投票,集群不能接受新的value,对于由此多数派中的Proposer发起的投票,因B3约束value已确定,所以只能返回client CONFLICT,value值不会再变。当然这里的状态机失败和业务逻辑无关,是指是否成功调用了状态机,那如果状态机返回的错误码是超时又会怎样?超时有可能状态机成功,也有可能状态机失败,Learner此时既不能认为成功,也无法认为失败,我认为状态机应该要记下已执行过的最大的InstanceId,且Id需要是连续的,如果下次Learner又提交相同的InstanceId过来,需要能够幂等(例如version实现的CAS乐观锁也可以),否则都会有问题。

5.机器重启后的PaxosLog Replay机制

通过看PhxPaxos,其重启初始化是Apply Checkpoint+ Replay PaxosLog,但对于PaxosLog中最近的一条是没有Replay的,究其原因是最近的一条PaxosLog不一定是达到多数派accept的log,因此不能直接重放。
我曾在wiki上提了如下问题:
“假设一个集群有ABC三台机器(在同一机房),正常流程达成一轮决议后,机房突然停电了,ABC无一幸免,那么当ABC三台机器各自重启后,都加载不到最近达成的决议,不能重放到状态机,那么这个已经达成的决议是不是会丢失?但是已经告诉client成功了,丢失是肯定不能接受的”,
PhxPaxos作者之一unixliang回复如下(在此对作者表示感谢!):
“假设llEndInstanceID(最近的PaxosLog)的提议是chosen的,这里有两种办法保证线性一致读:

  • 1)待master选出来后读master,master选举成功前llEndInstanceID的提议会apply到状态机;
  • 2)如果不需要master,那需要做一次paxos决议才能读最新数据,这和方法1类似。”

所以,根据作者的回复,都需要一次Paxos投票(选主也是一次Paxos投票)来恢复已被多数派Accept的值,若llEndInstanceID不是多数派accept的值,必然会被更大的ProposalId已accept的value冲掉,因此B3约束依然正确。


结语:不足指出欢迎批评指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值