什么是TCC事务
TCC是 Try,Confirm ,Cancel,三个单词的缩写,TCC要求每个分支事务需要实现三个操作:
预处理Try,确定Confirm ,撤销Cancel。Try操作做业务的检查和资源预留,Confirm做业务确定操作, Cancel实习一个和Try相反的操作及回滚操作,TM(全局事务管理器)首先发起所有分支事务的try操作,任何一个分支事务的try操作失败,TM将会发起除失败分支的所有分支事务的Cancel,若try都成功,TM将会发起所有分支事务的Confirm 操作,Confirm 或者Cancel执行失败TM会进行重试。
1. Try
阶段做业务检查(一致性)及资源的预留,此阶段仅为一个初步操作,和后续的Confirm 才是一个完整业务逻辑
2. Confirm
阶段做确定提交,Try阶段的所有分支事务都执行成功后开始执行Confirm ,通常情况下,采用TCC则认为Confirm 阶段不会出错,try都成功了则Confirm 必须得成功,若出现错误,需要引入重试机制或者人工处理。
3. Cancel
业务取消阶段,Try阶段的分支事务有一个出现失败后开始执行Cancel,通常情况下,采用TCC则认为Cancel阶段不会出错,try都成功了则Cancel必须得成功,若出现错误,需要引入重试机制或者人工处理。
-
成功情况
-
失败情况
空回滚
在没有调用TCC资源Try方法的情况下,调用了二阶段的Cancel方法, Cancel方法需要识别出这是一个空回滚,然后直接返回成功。出现原因是当一个分支事务所在服务宕机或网络异常,分支事务调用记录为失败,这个时候其实是没有执行Try阶段,当故障恢复后,分布式 事务进行回滚则会调用二阶段的Cancel方法,从而形成空回滚。
解决思路:关键就是要识别出这个空回滚。在try执行时写入一条执行记录,在回滚的时候先去判断try是否已经执行过了
幂等性
通过前面介绍已经了解到,为了保证TCC二阶段提交重试机制不会引发数据不一致,要求TCC的二阶段Try、Confirm 和Cancel接口保证幂等,这样不会重复使用或者释放资源。如果幂等控制没有做好,很有可能导致数据不一致等严重问题。
解决思路:运行时增加执行状态记录,每次执行前都查询该状态。
悬挂
悬挂就是对于一个分布式事务,其二阶段Cancel接口比Try接口先执行。出现原因是在RPC调用分支事务try时,先注册分支事务,再执行RPC调用,如果此时RPC调用的网络发生拥堵,通常RPC调用是有超时时间的, RPC超时以后, TM就会通知RM回滚该分布式事务,可能回滚完成后, RPC请求才到达参与者真正执行,而一个Try方法预留的业务资源,只有该分布式事务才能使用,该分布式事务第一阶段预留的业务资源就再也没有人能够处理了,对于这种情况 ,我们就称为悬挂,即业务资源预留后没法继续处理。
解决思路: 解决思路是如果二阶段执行完成,那一阶段就不能再继续执行。在执行一阶段事务时判断在该全局事务下,"分支事务记录”表中是否已经有二阶段事务记录,如果有则不执行Try。
解决方案 Hmily分布式事务框架
官网 https://dromara.org/zh/projects/hmily/overview/
框架帮我们做了悬挂处理,但是重试机制的存在还是需要用户自行处理幂等性问题
快速体验
根据说明修改配置文件
启动好项目打开swagger看看作者写的测试接口文档
这里直接来试试第一个mockAccountWithTryException接口
confirmMethod方法中执行修改订单成功操作,cancelMethod方法中执行修改订单失败操作
去账户服务扣减金额
发现账号服务直接抛异常
那么来说订单服务执行回滚会把订单修改为3 失败的状态
调用接口
发现这时数据库中的订单的确是3说明分布式事务控制成功
这里只做简单演示,项目中的示例还是比较全的
学习资料:黑马分布式事务解决方案 https://www.bilibili.com/video/BV1FJ411A7mV?p=17&share_source=copy_web
Hmily官网: https://dromara.org/zh/projects/hmily/overview/