分布式事务(第05篇)分布式事务解决方法-TCC
一 什么是TCC
TCC将每个分支事务都分成三个部分(Try、Confirm、Cancel):
- Try:业务检查及资源预留。
- Confirm:真正执行业务,不做任何业务检查。使用Try阶段预留的资源。
- Cancel:实现回滚操作,释放资源。
二 TCC实现分布式事务的流程
- 第一阶段:全局事务管理器分别调用所有分支事务,所有分支事务进行Try操作,当所有分支事务的Try操作都成功,或者某部分分支事务的Try操作失败,都进入第二阶段。
- 第二阶段:如果第一阶段所有分支事务Try都成功执行,则全局事务管理器通知所有分支事务进行Confirm操作,否则,通知所有分支事务进行Cancel操作。
成功图例:
失败图例:
三 举例说明TCC流程
场景:A账户给B账户转30块,AB在不同的服务。
方案1:
A服务: Try{ 检查A账户余额是否大于30元。 A账户扣减30元。 } Confirm{ 空。 } Cancle{ A账户增加30元。 }
B服务: Try{ B账户增加30元。 } Confirm{ 空。 } Cancle{ B账户扣减30元。 }
方案1存在的问题:
- 由于网络原因,A服务的Try没有执行,分支超时,则全局事务通知所有分支事务进行Cancel,那A账户就多了30元。
- Try、Confirm、Cancel都是有单独的线程去执行,且会出现重复调用,不支持幂等性。
- B服务执行Try后账户B增加了30元,其他服务将这30元使用了,后因为某种原因AB分支事务需要执行Cancel,B账户就不够30元了。
- 与1类型,B服务的Try没有执行,分支超时,则全局事务通知所有分支事务进行Cancel,那B账户就少了30元。
问题解决:
- A服务执行Cancel前判断A服务是否执行了Try。
- AB服务增加幂等性。
- B服务在Confirm中实现增加30元。
- B服务执行Cancel前判断B服务是否执行了Try。
优化后的方案2:
A服务: Try{ 增加幂等性。 判断是否已经执行了Cancel。若Cancle已执行,则不执行Try,反之则执行Try。 检查A账户余额是否大于30元。 A账户扣减30元。 } Confirm{ 空。 } Cancle{ 增加幂等性。 判断是否已经执行了Try。若Try未执行,则不执行Cancel,反之则执行Cancel。 A账户增加30元。 }
B服务: Try{ 空。 } Confirm{ 增加幂等性。 B账户增加30元。 } Cancle{ 空。 }
由此我们可以发现使用TCC需要注意一些问题。
四 TCC需要注意的三种异常:
- 空回滚
执行Cancel时需要判断当前分支事务是否已经执行Try。 - 悬挂
执行Try时需要判断当前分支事务是否已经执行Cancel。 - 幂等性
由于Confirm和cancel失败需进行重试,因此需要实现幂等性。
五 TCC与2PC区别
TCC本质上也是二阶段提交协议,但他们又有很大不同:
- TCC作用与服务层,2PC作用于资源层。(TCC开发人员通过业务代码实现数据提交与回滚,2PC基于数据库厂商原生协议,由数据库层面实现数据提交与回滚。)
- TCC三个接口逻辑由开发人员编写,2PC由数据库厂商或第三方编写。
- 由于以上两原因,TCC可以自由控制资源锁定的粒度。
- TCC侵入业务逻辑过强,每个分支事务都需要实现Try、Confirm、Cancel三个接口,改造成本高。
六 TCC缺点
- 代码侵入性太强,每个分支事务都得实现Try、Confirm、Cancel。(这一点我可难了,代码量庞大,耦合性高..手动狗头)
- 幂等性难以控制。
七 TCC的实现框架
ByteTCC,TCC-transaction,Hmily。
相关推荐
loviezhang 2020-06-16
亦碎流年 2020-04-30
憧憬 2020-01-05
wangyjbk 2019-12-27
loviezhang 2019-10-29
caifengguo 2019-01-29
一览众山小 2018-08-22
zhqianwei 2011-08-01
alexdeblog 2010-06-27
HerryDong 2018-08-22
shixiaoguo0 2017-05-09
Mrwind 2019-06-27
数据库之扑朔迷离 2019-06-26
齐来军的csdn 2019-05-28
追梦者的部落格 2019-05-27
盘山牛 2019-05-31
wxuande 2019-05-23
frommymind 2018-11-25
ningshuaichen 2018-12-17