什么是TCC,TCC是Try、Confirm、Cancel这三个词的缩写,由PatHelland于2007年首次发表名为《Life beyond Distributed Transactions:an Apostate’s Opinion》的论文呈现。TCC组成TCC分为3个阶段Try阶段:尝试执行,完成所有业务检查(一致性),预留必要的业务资源(准隔离)Confirm阶段:如果Try的所有分支都成功,则进入Confirm阶段。Confirm实际执行业务,不做任何业务检查,只使用Try阶段预留的业务资源。Cancel阶段:如果所有分支中有一个Try失败,则进入Cancel阶段。Cancel释放Try阶段预留的业务资源。在TCC分布式事务中,有3个角色,与经典的XA分布式事务相同:AP/应用程序,发起全局事务,定义全局事务中包含哪些事务分支RM/资源管理器,负责分支交易各种资源的管理TM/transactionmanager负责协调全局交易的正确执行,包括Confirm和Cancel的执行,以及处理网络异常。如果我们要进行一个类似于银行跨行转账的业务,分别在不同的微服务中转出(TransOut)和转入(TransIn),一个成功完成TCC交易的典型时序图如下:TCC实践接下来,我们将详细制定TCC交易。我们例子中使用的分布式事务框架是dtm,它很好地支持分布式事务。优雅。下面详细介绍TCC的组合下面我们来编写实体的Try/Confirm/Cancel的处理函数@RequestMapping("TransOutTry")publicMapTransOutTry(){logger.info("TransOutTry");Mapresult=newHashMap<>();result.put("dtm_result","SUCCESS");返回结果;}@RequestMapping("TransOutConfirm")publicMapTransOutConfirm(HttpServerResponseresponse){logger.info("TransOutConfirm");Mapresult=newHashMap<>();result.put("dtm_result","SUCCESS");返回结果;}@RequestMapping("TransOutCancel")publicMapTransOutCancel(){logger.info("TransOutCancel");Mapresult=newHashMap<>();result.put("dtm_result","SUCCESS");返回结果;}@RequestMapping("TransInTry")publicMapTransInTry(){记录器。信息(“TransInTry”);Mapresult=newHashMap<>();result.put("dtm_result","SUCCESS");返回结果;}@RequestMapping("TransInConfirm")publicMapTransInConfirm(){logger.info("TransInConfirm");Mapresult=newHashMap<>();result.put("dtm_result","SUCCESS");返回结果;}@RequestMapping("TransInCancel")publicMapTransInCancel(){logger.info("TransInCancel");Mapresult=newHashMap<>();result.put("dtm_result","SUCCESS");返回结果;}至此,各个子事务的处理函数都OK了,接下来启动TCC事务,进行分支调用@RequestMapping("fireTcc")publicStringfireTcc(){Functionfunction=TccController::tccTrans;返回tcc.tccGlobalTransaction(函数);}publicstaticBooleantccTrans(Tcctcc){尝试{booleana=tcc.callBranch("",svc+"/TransOutTry",svc+"/TransOutConfirm",svc+"/TransOutCancel");布尔b=tcc.callBranch("",svc+"/TransInTry",svc+"/TransInConfirm",svc+"/TransInCancel");返回一个&&b;}catch(Exceptione){e.printStackTrace();}返回假;至此,一个完整的TCC分布式事务就写完了如果你想完整的运行一个成功的例子,那么参考这个例子yedf/dtmcli-java-sample,运行起来很简单#Deploymentstartdtm#需要docker版本18以上gitclonehttps://github.com/yedf/dtmcddtmdocker-composeup#创建另一个命令行gitclonehttps://github.com/yedf/dtmcli-java-sample.gitcddtmcli-java-sample#编译并运行示例main/src/main/java/com/github/viticis/dtmclijavaexamples/DtmcliJavaSampleApplicationTCC的回滚如果银行在给用户2转账的时候发现用户2的账户异常,没有返回怎么办?我们可以通过让TransIn返回失败来模拟这种情况@RequestMapping("TransInTry")publicMapTransInTry(){logger.info("TransInTry");Mapresult=newHashMap<>();result.put("dtm_result","FAILURE");返回结果;}我们给出了交易失败交互的时序图。这个和成功的TCC的区别在于,当一个子事务失败时,后面会回滚。对于全局事务,调用每个子事务的Cancel操作,保证全局事务全部回滚。在TCC交易模式下,很多读者会问,如果Confirm/Cancel失败了怎么办?这是个好问题,说明你在深入思考TCC交易模型。第一种情况是暂时性的失败,比如网络故障,应用或数据库宕机,重试此类错误,最后会返回成功;另一种情况是商业失败。根据TCC协议,资源在第一阶段被锁定,以确保足够的资源可以让Confirm/Cancel执行。也就是说,在程序逻辑上,Confirm/Cancel是不允许返回业务失败的。如果出现业务故障,就是bug,需要开发者手动修复bug。小结在本文中,我们介绍了TCC的理论知识,并通过一个例子,给出了一个完整的TCC事务编写流程,涵盖了正常成功完成和成功回滚的情况。相信读者通过本文对TCC有了更深入的了解。更全面的分布式事务知识请参考《分布式事务最经典的七种解决方案》本文所用示例摘自yedf/dtm,支持多种事务模式:TCC、SAGA、XA,事务消息的跨语言支持,已经支持golang、python、Java、PHP、nodejs等语言,参考语言SDK。提供子事务屏障功能,优雅解决幂等、挂起、空值补偿等问题。看完这篇干货,欢迎大家访问https://github.com/yedf/dtm项目,给个star支持!