分布式协议——2PC和3PC概述
所谓协议,就是交流的约定的流程和格式。
比如,当你在宿舍门口敲门,门内说:“天王盖地虎”,你答复:“宝塔镇河妖”,于是两个人就能否开门进去,达成了一致。
分布式一致性协议,自然比上面的复杂一些。
又比如,用户购买商品下单,会需要:
- A活动服务:冻结优惠名额等资源
- B支付服务:冻结付款金额(假设是平台代币)
- C库存服务:冻结库存
A、B、C服务就下单动作,达成的资源状态一致:
- 服务A扣掉优惠名额
- 服务B扣掉付款金额,保存正确的余额(平台代币)
- 服务C扣掉相应库存量
这一些列动作,是一个事务,要么全部达成,下单成功;要么全部操作不生效,下单失败。 但是分布式环境下,存在网络分区隔离,网络延时,服务宕机, 三态等问题,要实现这样的分布式事务,需要一种协议来让大家协作。
那以此为例,我们来理解一下2PC和3PC协议。
2PC
协议
定义:顾名思义,2 Phase Commit, 先发起人先拉票,大家都同意后,发起人再通知事务提交。
阶段一
- 发起preCommit: 通知服务A,B,C执行业务逻辑
- ack: ABC会分别检查前置条件,然后执行业务
- 条件不满足,返回失败 ack fail
- 条件满足,执行业务逻辑,返回成功 ack success, 锁定资源,等待下一步commit
阶段二
如果阶段一,大家都返回ack success, 那么就发起commit
- 发起commit请求
- ack:ABC执行本地事务提交,释放资源,并ack
如果阶段一,有人返回ack fail, 那么就发起rollback
- 发起rollback请求
- ack:ABC执行本地事务回滚,释放资源,并ack
异常
作为服务ABC,可能会面对的异常情况(按需脑补图例):
- 阶段一preCommit没有收到,无感
- 阶段二commit没有收到,资源处于锁定状态,如何应对:
- 死等,不见不散,资源一直锁定 【不合适】
- 等一段时间,如果commit一直未到达, 执行commit 【不合适:可能有的返回了ack fail,未执行业务逻辑】
- 等一段时间,如果commit一直未到达, 执行rollback【恰当】
作为调用发起者Actor,可能会面对的异常情况(按需脑补图例):
- 阶段一ack没有全部收到:无法确定下游是否已经执行业务逻辑,
- 可多次重试preCommit,然后发起回滚
- 阶段二ack没有全部收到:无法确定下游是否已经提交事务,
- 多次重试commit
- 部分已经commit,无法执行回滚
注意:服务ABC对每个操作都要有幂等性,便于调用者Actor重试。
总结
2PC实现细节:
- Actor在未收到ack时,可多次重试
- 服务ABC对操作要具有幂等性
- 阶段二中,当服务ABC等待commit超时,执行rollback
2PC存在不一致的情况:
- 情况:第二步的commit,如果服务ABC有的没收到,那么只有部分执行commit,而另一部分等待超时后回滚,出现严重的数据不一致。
2PC的性能问题:
第一步中,并发情况可能会存在,服务ABC在一段时间内,总有不满足的情况,导致资源频繁加锁和释放锁
譬如有3个Actor,一起开始下单,可能存在多次加锁和释放锁 - Actor1发起preCommit,C不满足,AB满足(锁定资源), 随后Actor1发起AB资源释放 - Actor2发起preCommit,B不满足,AC满足(锁定资源), 随后Actor2发起AC资源释放 - Actor3发起preCommit,都满足,随后Actor3发起commit
如果是并发情况,因为部分人下大单,库存明显不足,部分人余额不足(假设是平台内代币),导致频繁且无意义的资源加锁和释放。
3PC
协议
定义:顾名思义,3 Phase Commit。 相对2PC,多了一个阶段。其实是将2PC的阶段一拆分为2个子阶段。
- 阶段一(2PC.1-1): Actor发起preCheck,检查资源是否满足,不锁定资源(如库存够不够,余额够不够等)
- 阶段二(2PC.1-2): Actor发起preCommit,服务ABC执行业务逻辑,锁定资源(同2PC的阶段一)
- 阶段三 (2PC.2): Actor发起commit/rollback指令,服务ABC执行commit/rollback
3PC相对2PC的改进点分析
- 增加前置检查阶段:解决2PC中的性能问题,减少无效的资源加锁和释放锁动作,或者说锁的粒度比2PC要小
- 服务ABC在阶段二(2PC.1-2)之后,一直等待commit或rollback指令,等待超时后,执行commit(区别于2PC)
- 既然可以进入阶段二(2PC.1-2),那么前一阶段已经检测通过,大家都表示资源没有问题,乐观认为基本可以commit
异常
3PC存在的不一致情况:并发情况下,多个Actor同时下单,可能会导致不一致
- 阶段一(2PC.1-1): 多个Actor发起preCheck, 这时,服务ABC均返回条件满足
- 阶段二(2PC.1-2):Actor1发起preCommit,随后,Actor1收到来自服务C的ack fail,库存不足了
- 阶段三 (2PC.2):Actor1发起rollback,但是网络原因,A或B等待阶段三指令超时,执行commit, 出现不一致(钱和优惠券都用了,库存没减)
总结
所以3PC只是优化了2PC阶段一的性能,两者均无法保证达到一致性。 关键服务ABC可能等不到最后一个阶段的commit,此时无论选择rollback或commit,都有不一致的风险。
伏笔
到这里,我不由得想,Google Chubby的作者Mike Burrows说,世上只有一种一致性算法,那就是Paxos算法。那2PC和3PC既然无法保证达到一致性,这玩意存在意义是什么,TM会有人用么?
待续~