原创

分布式事务之3PC

本文继续分布式事务:3PC,建议大家先看一下:2PC

回顾2PC

举个例子,A邀请B、C一起打王者荣耀,2PC过程如下:

A是协调者,B、C是参与者。

阶段1(prepare阶段)

step1-1:A微信B

step1-1-1:A->B:有空么,我们约C一起王者荣耀
step1-1-2:B->A:有空
step1-1-3:A->B:那你现在就打开电脑,登录王者荣耀,你等着,我去通知C,然后开个房间
step1-1-4:B->A:已登录

step1-2:A微信C

step1-2-1:A->C:有空么,我约了B一起王者荣耀
step1-2-2:C->A:有空
step1-2-3:A->C:那你现在就打开电脑,登录王者荣耀,你等着,我去开个房间
step1-2-4:C->A:已登录

阶段2(commit阶段)

此时B、C都已经登录王者容易了,然后A登录王者荣耀开了个房间

step2-1:A微信B

step2-1-1:A->B:房间号是xxx,你可以进来了
step2-1-2:B->A:我的,我进来了

step2-2:A微信C

step2-2-1:A->C:房间号是xxx,你可以进来了
step2-2-2:C->A:我的,我进来了

然后3个人开始爽歪歪了。

2PC一些异常情况

情况1:step1-2-4超时,导致A无法收到C已登录的消息

此时A不知道C是什么情况,但是2PC中协调者这边有超时机制,如果协调者给参与者发送信息,长时间得不到回应时,将作为失败处理,此时A会给B和C发送rollback消息,让B和C都进行回滚,即取消游戏。

情况1:step1-1之后,协调者A挂了

此时B已经打开电脑在那等着了,却始终不见A、C的踪影,相当苦恼,也不知道还要等多久,苦逼!

情况2:阶段1之后,协调者A挂了

此时B、C登录账号了,也等了十几分钟了,就是不见A的踪影,也只能干等着,什么事情也做不了。

情况3:step2-2-1出现问题,C网络故障

此时C收不到A发送过来的消息,结果是导致A和B都已经进入房间了,就缺C了,游戏无法正常开始,导致最终的结果和期望的结果无法一致(期望3个人一起玩游戏,实际上房间里只有2个人)

总的来说,2PC主要有2个问题

参与者干等的问题

参与者只能按照协调者的指令办事,当收不到协调者的指令的时候,参与者只能坐等,在db中的效果,操作的数据会被一直锁着,导致其他操作者被阻塞。

数据不一致的问题

commit阶段,协调者或者参与者挂掉,都可能导致最终数据不一致的问题。

3PC

3PC主要解决了2PC中commit阶段参与者干等的问题,2PC中commit阶段,若协调者挂了,参与者不知道如何走了。2PC中只有协调者这边有超时机制,而3PC中,协调者和参与者这边引入了超时机制,commit阶段,若参与超过一定的时间收不到commit命令,参与者会自动提交,从而解决了2PC中资源长时间被锁的问题。

3PC相对于2PC,多了一个阶段,相当于把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommitPreCommitDoCommit三个阶段。

阶段1:CanCommit阶段

之前2PC的一阶段是本地事务执行结束后,最后不Commit,等其它服务都执行结束并返回Yes,由协调者发出commit才真正执行commit,而这里的CanCommit指的是 尝试获取数据库锁 如果可以,就返回Yes。

这阶段主要分为2步

事务询问:协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与的响应。

响应反馈:参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No,然后事务就结束了,此时参与者并没有执行任务任何操作。

阶段2:PreCommit阶段

在阶段一中,如果所有的参与者都返回Yes的话,那么就会进入PreCommit阶段进行事务预提交。这里的PreCommit阶段 跟上面的第一阶段是差不多的,只不过这里 协调者和参与者都引入了超时机制(2PC中只有协调者可以超时,参与者没有超时机制)。

阶段3:DoCommit阶段

这里跟2pc的阶段二是差不多的。

王者荣耀3PC过程

正常的过程

阶段1(CanCommit阶段)

step1-1:A微信B
step1-1-1:A->B:有空么,我们约C一起王者荣耀
step1-1-2:B->A:有空
step1-2:A微信C
step1-1-1:A->B:有空么,我们约B一起王者荣耀
step1-1-2:B->A:有空

阶段2(PreCommit阶段)

step2-1:A微信B
step2-1-1:A->B:你现在就打开电脑,登录王者荣耀,等我消息,如果10分钟没消息,你就自己开个房间玩吧(参与者超时机制)。
step2-1-2:B->A:已登录
step2-2:A微信C
step2-2-1:A->C:那你现在就打开电脑,登录王者荣耀,等我消息,如果10分钟没消息,你就自己开个房间玩吧(参与者超时机制)。
step2-2-2:C->A:已登录

阶段3(DoCommit阶段)

此时B、C都已经登录王者容易了,然后A登录王者荣耀开了个房间

step3-1:A微信B
step3-1-1:A->B:房间号是xxx,你可以进来了
step3-1-2:B->A:我的,我进来了
step3-2:A微信C
step3-2-1:A->C:房间号是xxx,你可以进来了
step3-2-2:C->A:我的,我进来了

然后3个人开始爽歪歪了。

异常的几种情况

阶段1异常

此时并没有进行事务操作,所以这个阶段出问题了,可以直接结束事务。

阶段2,参与者挂了

参与者挂了没关系,协调者直接通知其他参与者回滚。

阶段2,协调者挂了

协调者挂了,由于参与者引入了超时机制,所以参与者并不会无限期等待,等待一定的时间之后,会自动提交本地事务。

虽然这个超时机制解决了无限等待的问题,却并没有解决一致性的问题,比如上面3PC中step2-1:A微信B之后,协调者挂了,此时A已经登录了,但是C未收到A要求登录的消息,超时10分钟之后,A自己去开了一个游戏玩起来了,结果和期望的结果不一致了。

3PC存在的问题

虽然解决了2PC中参与者长时间阻塞的问题(资源长时间无法释放的问题),但是并没有解决一致性的问题。

有没有办法解决这些问题?

有,TCC,下一篇文章介绍,敬请期待!

推荐一个高质量的公众号

这里给大家推荐一个公众号:Java充电社,这个号中会定期发布一些高质量的java专题视频,目前已经发布了大量高质量的学习视频,大家可以去瞅瞅,欢迎关注。

file

正文到此结束
本文目录