TCC是Try、Confirm、Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try、确认Confirm、撤销Cancel。

1、Try 阶段是做业务检查(一致性)及资源预留(隔离),此阶段仅是一个初步操作,它和后续的Confirm一起才能真正构成一个完整的业务逻辑。

2、Confirm 阶段是做确认提交,Try阶段所有分支事务执行成功后开始执行Confirm。通常情况下,TCC认为Confirm阶段是不会出错的,若Confirm阶段真的出错了,则重试或人工处理。

3、Cancel 阶段是在业务执行错误需要回滚的状态下执行分支事务的业务取消,预留资源释放。通常情况下,TCC认为Cancel阶段也是一定成功的,若Cancel阶段真的出错了,则重试或人工处理。

TM(事务管理器)首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所有分支事务的Cancel操作;若try操作全部成功,TM将会发起所有分支事务的Confirm操作,其中Confirm/Cancel操作若执行失败,TM会进行重试。

所有try都成功

有一个try失败

特别提醒

  1. 所有分支事务的try阶段执行成功,则会执行confirm阶段。TCC认为confirm阶段一定会执行成功,如果confirm执行失败,则会重试或者人工处理错误。

  1. 任何一个分支事务的try阶段执行失败,则会执行cancel阶段。TCC认为cancel阶段一定会执行成功,如果cancel执行失败,则会重试或者人工处理错误。

TCC需要注意三种异常处理分别是:空回滚、幂等、悬挂。

空回滚

事务管理器调用服务的try操作,可能会出现因为丢包而导致的网络超时,导致应用的try阶段没执行,事务管理器认为执行try超时,会触发cancel操作。这就导致cancel比try先执行。

悬挂

1、事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因网络拥堵而导致的超时。

2、此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,Cancel 执行正常。

3、在此之后,拥堵在网络上的一阶段 Try 数据包被 TCC 服务收到,出现了二阶段 Cancel 请求比一阶段 Try 请求先执行的情况。

4、此 TCC 服务在执行晚到的 Try 之后,将永远不会再收到二阶段的 Confirm 或者 Cancel ,造成 TCC 服务悬挂。

幂等

try、confirm、cancel都会被重复调用,需要做幂等处理。

处理空回滚、悬挂、幂等

可以使用日志表,来解决 空回滚、悬挂、幂等。

新建3张表

try阶段日志表local_try_log

字段

注释

tx_no

全局事务id

create_time

创建时间

confirm阶段日志表local_confirm_log

字段

注释

tx_no

全局事务id

create_time

创建时间

cancel阶段日志表local_cancel_log

字段

注释

tx_no

全局事务id

create_time

创建时间

例子

从银行1转账10元给银行2,使用TCC方案

方案1

银行1

try:幂等校验,查找try日志(全局事务id是主键)悬挂处理,查找confirm、cancel日志(全局事务id是主键)检查余额是否够10元锁定10元插入try日志(全局事务id是主键)
confirm:幂等校验,查找confirm日志(全局事务id是主键)扣减10元删除锁定10元插入confirm日志(全局事务id是主键)
cancel:cancel幂等校验,查找cancel日志(全局事务id是主键)空回滚处理,查找try日志(全局事务id是主键)增加余额10元(回滚)删除锁定10元插入cancel日志(全局事务id是主键)

银行2

try:幂等校验,查找try日志(全局事务id是主键)悬挂处理,查找confirm、cancel日志(全局事务id是主键)插入待激活10元插入try日志(全局事务id是主键)
confirm:幂等校验,查找confirm日志(全局事务id是主键)正式增加30元删除待激活10元插入confirm日志(全局事务id是主键)
cancel:空

由于业务很简单,上面的流程还可以取消锁定,解锁的操作,直接在银行1的try中扣减10元,流程如下。

方案2

银行1

try:幂等校验,查找try日志(全局事务id是主键)悬挂处理,查找confirm、cancel日志(全局事务id是主键)检查余额是否够10元扣减10元插入try日志(全局事务id是主键)
confirm:空
cancel:cancel幂等校验,查找cancel日志(全局事务id是主键)空回滚处理,查找try日志(全局事务id是主键)增加余额10元(回滚)插入cancel日志(全局事务id是主键)

银行2

try:空
confirm:幂等校验,查找confirm日志(全局事务id是主键)正式增加30元插入confirm日志(全局事务id是主键)
cancel:空

Hmily实现方案2的代码

服务1

@Service
@Slf4j
public class Bank1ServiceImpl implements Bank1Service {@AutowiredAccountInfoDao accountInfoDao;@AutowiredHmilyLogDao hmilyLogDao;@AutowiredBank2Client bank2Client;@Override@Transactional(rollbackFor = Exception.class)@Hmily(confirmMethod = "confirm", cancelMethod = "cancel")public void updateAccountBalance(String msg, Double amount) {// 全局事务idString transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank1 try 开始,transId={}", transId);// 幂等判断int existTry = hmilyLogDao.isExistTry(transId);// 通故全局事务id查找到try日志,表明已经只执行过tryif (existTry > 0) {log.info("已经执行过try,无需重复执行try,transId={}", transId);return;}// 悬挂处理int existConfirm = hmilyLogDao.isExistConfirm(transId);int existCancel = hmilyLogDao.isExistCancel(transId);// 通故全局事务id查找到confirm、cancel日志,表明已经只执行过confirm、cancelif (existConfirm > 0 || existCancel > 0) {log.info("confirm,cancel有一个已经执行过,try不能再次执行,transId={}", transId);return;}// 制造空回滚if (StringUtils.equals("制造空回滚", msg)) {throw new RuntimeException("try方法没修改数据库就抛出异常,cancel方法会执行,形成空回滚,transId=" + transId);}// blank1减金额accountInfoDao.subtractAccountBalance("1", amount);// 添加try日志记录,try日志和扣减余额在同一个本地事务中,要么都成功,要么都失败// 日志的组件id必须是全局事务id,如果同一个事物重复调用try,到这一步会报主键重复hmilyLogDao.addTry(transId);// 远程调用Boolean result = bank2Client.transfer(msg, amount);if (!result) {throw new RuntimeException("调用bank2失败");}// bank1调用bank2成功后,发生异常,模拟回滚if (StringUtils.equals("bank1调用bank2成功后,发生异常,模拟回滚", msg)) {throw new RuntimeException("bank1调用bank2成功后,发生异常,模拟回滚,transId=" + transId);}}public void confirm(String accountNo, Double amount) {String transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank1 confirm 开始执行,transId={}", transId);}@Transactional(rollbackFor = Exception.class)public void cancel(String msg, Double amount) {// 全局事务idString transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank1 cancel 开始执行,transId={}", transId);// 幂等判断int existCancel = hmilyLogDao.isExistCancel(transId);if (existCancel > 0) {log.info("cancel已经执行过,无需重复执行,transId={}", transId);return;}// 处理空回滚int existTry = hmilyLogDao.isExistTry(transId);if (existTry == 0) {log.info("try未执行过,不能执行cancel,transId={}", transId);return;}// bank1回滚,加钱accountInfoDao.addAccountBalance(msg, amount);// 添加日志hmilyLogDao.addCancel(transId);}}
@Service
@Slf4j
public class Bank2ServiceImpl implements Bank2Service {@AutowiredAccountInfoDao accountInfoDao;@AutowiredHmilyLogDao hmilyLogDao;@Override@Hmily(confirmMethod = "confirm", cancelMethod = "cancel")public void updateAccountBalance(String msg, Double amount) {String transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank2 try 开始执行,transId:{}",transId);}@Transactional(rollbackFor = Exception.class)public void confirm(String msg, Double amount) {// 全局事务idString transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank2 confirm 开始执行,transId:{}",transId);int existConfirm = hmilyLogDao.isExistConfirm(transId);if (existConfirm > 0) {log.info("bank2 confirm 已经执行过,无需再次执行,transId", transId);return;}// bank2加钱accountInfoDao.addAccountBalance("2", amount);// 添加confirm日志hmilyLogDao.addConfirm(transId);// bank2 confirm,抛出异常,会重试if (StringUtils.equals("confirm抛出异常会重试", msg)) {throw new RuntimeException("confirm抛出异常会重试,transId=" + transId);}}public void cancel(String msg, Double amount) {String transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank2 cancel 开始执行,transId:{}",transId);}}

分布式事务解决方案——TCC相关推荐

  1. 分布式事务解决方案:2PC,TCC以及基于消息的最终一致性

    各种形态的分布式事务 分布式事务有多种主流形态,包括:基于消息实现的分布式事务 基于补偿实现的分布式事务 基于TCC实现的分布式事务 基于SAGA实现的分布式事务 基于2PC实现的分布式事务 这些形态 ...

  2. 分布式事务解决方案汇总:2PC、消息中间件、TCC、状态机+重试+幂等(转)

    数据一致性问题非常多样,下面举一些常见例子.比如在更新数据的时候,先更新了数据库,后更新了缓存,一旦缓存更新失败,此时数据库和缓存数据会不一致.反过来,如果先更新缓存,再更新数据库,一旦缓存更新成功, ...

  3. 实践丨分布式事务解决方案汇总:2PC、消息中间件、TCC、状态机+重试+幂等

    本文节选自<软件架构设计:大型网站技术架构与业务架构融合之道>一书,余春龙著,由电子工业出版社博文视点出版,已获得授权.架构是一种综合能力,而不是某一方面的技能.也正因为如此,本书提供的是 ...

  4. java分布式事务——seata,tcc解决方案总结!

    目录 1.分布式事务基础理论 1.1.CAP理论 1.2.BASE理论 2.分布式事务解决方案之2PC(两阶段提交) 2.2.1 XA方案 2.2.2 Seata方案 2.2.3分布式事务解决方案之T ...

  5. 分布式事务专题(四):分布式事务解决方案之TCC

    目录: 基础概念 分布式事务理论 分布式事务解决方案之2pc 分布式事务解决方案之TCC(本章) 分布式事务解决方案之可靠消息最终一致性 分布式事务解决方案之最大努力通知 分布式事务综合案例分析 4. ...

  6. 分布式事务TCC方案——Hmily金融级柔性分布式事务解决方案介绍

    关于TCC的理论部分请参考:分布式事务基础理论--TCC 概述 目前市面上的TCC框架众多(都是国内的呢): 框架名称 GitHub地址 tcc-transaction https://github. ...

  7. Seata聚合 AT、TCC、SAGA 、 XA事务模式打造一站式的分布式事务解决方案

    Seata Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务.在 Seata 开源之前,Seata 对应的内部版本在阿里经济体内部一直扮演着分布式一 ...

  8. 常用的分布式事务解决方案介绍有多少种?

    关于分布式事务,工程领域主要讨论的是强一致性和最终一致性的解决方案.典型方案包括: 两阶段提交(2PC, Two-phase Commit)方案 eBay 事件队列方案 TCC 补偿模式 缓存数据最终 ...

  9. EasyTransaction 1.3.0 发布,一站式分布式事务解决方案

    EasyTransaction 是一个一站式分布式事务解决方案,其包括了 TCC 事务,自动补偿(seata/fescar AT 功能),补偿事务,可靠消息,SAGA 等等多种事务模式,并能混合各种事 ...

最新文章

  1. wordexcelppt文档加密方式
  2. Eclipse 4.4.2 取消空格键代码上屏
  3. python正则表达式修饰符_python正则表达式,看完这篇文章就够了...
  4. Redis Cluster搭建方法简介22211111
  5. 服务核心 - 工具类
  6. .Net Core使用Ocelot网关(一) -负载,限流,熔断,Header转换
  7. 数据库sql课程设计_SQL和数据库-初学者完整课程
  8. 路考步骤七步走 科目三考试一定没问题!
  9. android 浏览器 pc一样大小,手机端不同浏览器[主流的,包括Android自带]对cookie的不同限制,如个数和大小,如何查看?...
  10. Dynamic Performance Tables not accessible Automatic Statistics disabled for this session
  11. python基础系列教程——Python3.x标准模块库目录
  12. 何为软件的Alpha、Beta、RC和GA发布版本?
  13. python requests text content_对python requests的content和text方法的区别详解
  14. 拓端tecdat|TensorFlow 2.0 keras开发深度学习模型实例:多层感知器(MLP),卷积神经网络(CNN)和递归神经网络(RNN)
  15. javaee实训报告总结_javaee实习报告.doc
  16. Ubuntu系统的百度网盘网络错误导致无法上传和下载文件问题解决方法
  17. linux下ScrollLock键盘灯不亮
  18. maven-assembly-plugin
  19. P7939 [B1] Alice Wins (easy version)--题解报告
  20. 将 PDF 文件拆分为多个同样页数 pdf 文件的 Windows Powershell 脚本

热门文章

  1. Vue 引入js文件并使用
  2. 转换HTML内容为PDF格式
  3. about hashCode again understand
  4. vue computed 与mounted 区别
  5. 10个企业网络安全建议,解决99%的网络安全问题
  6. offsetof 详解
  7. MATLAB—离散一元、二元、多元函数求导求梯度(二维、三维、多维空间)(diff和gradient)
  8. 几个cve漏洞库查询网站
  9. DMP文件的生成和使用
  10. 经济危机会影响软件质量吗?