百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

tcc-transaction分布式TCC事务框架搭建与实战(基于Dubbo/Dubbox)

ccwgpt 2024-09-26 07:51 26 浏览 0 评论


一、背景

有一定分布式开发经验的朋友都知道,产品/项目/系统最初为了能够快速迭代上线,往往不太注重产品/项目/系统的高可靠性、高性能与高扩展性,采用单体应用和单实例数据库的架构方式快速迭代开发;当产品/项目/系统做到一定规模的时候,原有的系统架构则不足以支撑义务发展需要,往往相同的业务则需要重复写很多次,导致代码大量冗余,难以维护和扩展,这时不得不对原有产品/项目/系统进行拆分,引入分布式的系统架构;而对原有产品/项目/系统进行拆分的过程中,对于业务和数据的拆分和迁移则成为了最为棘手的问题,尤其是在原有业务不能下线,拆分后的业务同时上线的场景下这种问题更加突出;项目拆分后,业务被拆分为多个独立的子业务分散到多个子系统中,而原有的单一数据库则被拆分到多个数据库中,拆分后的数据库则同样又面临着让人头疼的分布式事务的问题。

本文就针对项目拆分后数据库的分布式事务问题,基于tcc-transaction分布式TCC型事务进行框架的搭建,同时引入相关的实战案例,来解决让人头疼的分布式事务问题。


二、tcc-transaction框架介绍

介绍:tcc-transaction是开源的TCC补偿性分布式事务框架,Git地址:https://github.com/changmingxie/tcc-transaction

TCC为Try、Confirm、Cancel的缩写:try阶段预留资源尝试提交,confirm阶段确定提交,cancel取消提交释放资源。

1.2.x项目指南地址:https://github.com/changmingxie/tcc-transaction/wiki/%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%971.2.x

本文的例子为引入一个本人实际工作中的一个开发场景:创建资产,将资产信息同时同步到Mongo与ES的流程(ES代码不列出了,与mongo类似),整个流程保证数据一致


三、项目流程

1.下载1.2.x版本源码,并可能需要修改部分代码

因为是第三方包,所以需要自己打包到本地仓库。但包中spring版本为3.2.12.RELEASE,如果本地项目为4.x,比如本人的项目spring版本为4.3.4.RELEASE,如果不修改tcc中的spring版本,将报错无法启动,所以需要对原有框架源码进行相应的修改。

源码修改比较简单,如下


1.1 修改tcc-transaction总pom.xml文件

<!-- 第一处:修改版本为4.3.4  --><springframework.version>4.3.4.RELEASE</springframework.version> <!-- 第二处:修改版本为2.2.1  --><dependency>      <groupId>org.quartz-scheduler</groupId>      <artifactId>quartz</artifactId>      <version>2.2.1</version>      <exclusions>          <exclusion>              <groupId>c3p0</groupId>              <artifactId>c3p0</artifactId>          </exclusion>      </exclusions></dependency> <!-- 第三处:修改版本为2.5.3  --><dependency>       <groupId>com.alibaba</groupId>       <artifactId>dubbo</artifactId>       <version>2.5.3</version></dependency>


1.2 修改 Java类

tcc-transaction-spring/src/main/java/org/mengyun/tcctransaction/spring/recover/RecoverScheduledJob.java

该文件中 CronTriggerBean类在4.x中已经不存在,也是修改源码主要修改的地方。

修改其中的init方法,修改后如下:

public void init() {    try {        MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();        jobDetail.setTargetObject(transactionRecovery);        jobDetail.setTargetMethod("startRecover");        jobDetail.setName("transactionRecoveryJob");        jobDetail.setConcurrent(false);        jobDetail.afterPropertiesSet();         CronTriggerFactoryBean cronTrigger = new CronTriggerFactoryBean();        cronTrigger.setBeanName("transactionRecoveryCronTrigger");        cronTrigger.setJobDetail(jobDetail.getObject());         cronTrigger.setCronExpression(transactionConfigurator.getRecoverConfig().getCronExpression());        cronTrigger.afterPropertiesSet();         scheduler.scheduleJob(jobDetail.getObject(), cronTrigger.getObject());         scheduler.start();     } catch (Exception e) {        throw new SystemException(e);    }}

各位也可参考如下的修改:https://github.com/changmingxie/tcc-transaction/pull/84/files


1.3 打包并发布

这里我们通过Maven进行打包发布,命令为:

mvn -Dmaven.test.skip=true install

2.项目依赖


参考1.2.x使用指南,引入两个依赖(本人项目dubbo/dubbox框架,我使用并打包时版本为1.2.3.1)。调用方和提供方都需要引入依赖。

3.加载tcc-transaction.xml配置


原文中是配置在web.xml中,我个人试了一下放在dubbo web项目的web.xml中,但配置并没有被加载。该文件的意义只是希望项目启动时被加载,于是直接在dubbo中的一个spring的配置文件中引入,如下:

<!-- TCC Transaction --><import resource="classpath:tcc-transaction.xml" />

该文件里面提供各种aop逻辑,项目启动时扫描指定注解,并做增强。

4.设置TransactionRepository‘


需要为tcc配置数据源,可以是MySQL或其他nosql,本文使用mysql,其他可参见原指南文档。mysql配置如下:

<!--tcc--><bean id="tccDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">    <property name="driverClassName" value="${jdbc.driverClassName}" />    <property name="url" value="${jdbc.tcc.url}" />    <property name="username" value="${jdbc.username}" />    <property name="password" value="${jdbc.password}" />    <property name="initialSize" value="${dbcp.initialSize}" />    <property name="maxActive" value="${dbcp.maxActive}" />    <property name="maxIdle" value="${dbcp.maxIdle}" />    <property name="maxWait" value="${dbcp.maxWait}" />    <property name="poolPreparedStatements" value="${dbcp.poolPreparedStatements}" />    <property name="defaultAutoCommit" value="${dbcp.defaultAutoCommit}" />    <property name="timeBetweenEvictionRunsMillis" value="${dbcp.timeBetweenEvictionRunsMillis}" />    <property name="minEvictableIdleTimeMillis" value="${dbcp.minEvictableIdleTimeMillis}" /></bean> <bean id="transactionRepository"      class="org.mengyun.tcctransaction.spring.repository.SpringJdbcTransactionRepository">    <property name="dataSource" ref="tccDataSource"/>    <property name="domain" value="SAAS"/>    <property name="tbSuffix" value="_ASSET"/></bean> <bean class="org.mengyun.tcctransaction.spring.recover.DefaultRecoverConfig">    <property name="maxRetryCount" value="30"/>    <property name="recoverDuration" value="120"/>    <property name="cronExpression" value="0 */1 * * * ?"/>    <property name="delayCancelExceptions">        <util:set>            <value>com.alibaba.dubbo.remoting.TimeoutException</value>        </util:set>    </property></bean>


需要注意的点:

1.数据源必须配置新的,不能使用之前项目存在的dataSource的bean,也不能在同一库中,不然会导致tcc表数据与本地事务一起回滚,从而无法保存异常事务日志;

2.注意domain、tbSuffix的配置,这两项文档中并没有配置,但源码demo中配置了,用于数据库的表名称等,推荐配置;

3.最后的DefaultRecoverConfig项是可选的,用于恢复与重试,具体作用参考使用指南;

4.defaultAutoCommit必须为true(默认为true)

5.mysql建表脚本

根据以上的tbSufifix配置,脚本如下:

CREATE TABLE `tcc_transaction_asset` (  `TRANSACTION_ID` int(11) NOT NULL AUTO_INCREMENT,  `DOMAIN` varchar(100) DEFAULT NULL,  `GLOBAL_TX_ID` varbinary(32) NOT NULL,  `BRANCH_QUALIFIER` varbinary(32) NOT NULL,  `CONTENT` varbinary(8000) DEFAULT NULL,  `STATUS` int(11) DEFAULT NULL,  `TRANSACTION_TYPE` int(11) DEFAULT NULL,  `RETRIED_COUNT` int(11) DEFAULT NULL,  `CREATE_TIME` datetime DEFAULT NULL,  `LAST_UPDATE_TIME` datetime DEFAULT NULL,  `VERSION` int(11) DEFAULT NULL,  PRIMARY KEY (`TRANSACTION_ID`),  UNIQUE KEY `UX_TX_BQ` (`GLOBAL_TX_ID`,`BRANCH_QUALIFIER`)) ENGINE=InnoDB DEFAULT CHARSET=utf8

如果表名称不对,启动过程会报错,这时,对数据表做相应调整即可。


6.发布服务(重点)

6.1 dubbo接口
 /**  * @author binghe  * 资产相关的业务发布Dubbo服务  */public interface AssetCardService {     /**     * 测试预保存资产(状态为待确认)     */    @Compensable    int testSaveAssetCard(AssetCardModel model);     /**     * 确认保存资产到mysql(状态为正常)     */    int confirmMysqlSaveAssetCard(AssetCardModel model);     /**     * 取消保存资产到msyql(更新状态为删除)     */    int cancelMysqlSaveAssetCard(AssetCardModel model);     /**     * 预保存资产到mongo(状态为待确认)     */    @Compensable    void processMongo(AssetCardModel model);     /**     * 确认保存资产到mongo(状态为正常)     */    void confirmMongoSaveAssetCard(AssetCardModel model);     /**     * 取消保存资产到mongo(更新状态为删除)     */    void cancelMongoSaveAssetCard(AssetCardModel model); }


需要注意的点:1.对外提供服务的接口必须有@Compensable注解;2.对应的confirm与cancel方法必须声明为接口,不能声明为private,即使是public也不行,必须有接口。

3.最后的DefaultRecoverConfig项是可选的,用于恢复与重试,具体作用参考使用指南;

4.defaultAutoCommit必须为true(默认为true)

5.mysql建表脚本

根据以上的tbSufifix配置,脚本如下:

CREATE TABLE `tcc_transaction_asset` (  `TRANSACTION_ID` int(11) NOT NULL AUTO_INCREMENT,  `DOMAIN` varchar(100) DEFAULT NULL,  `GLOBAL_TX_ID` varbinary(32) NOT NULL,  `BRANCH_QUALIFIER` varbinary(32) NOT NULL,  `CONTENT` varbinary(8000) DEFAULT NULL,  `STATUS` int(11) DEFAULT NULL,  `TRANSACTION_TYPE` int(11) DEFAULT NULL,  `RETRIED_COUNT` int(11) DEFAULT NULL,  `CREATE_TIME` datetime DEFAULT NULL,  `LAST_UPDATE_TIME` datetime DEFAULT NULL,  `VERSION` int(11) DEFAULT NULL,  PRIMARY KEY (`TRANSACTION_ID`),  UNIQUE KEY `UX_TX_BQ` (`GLOBAL_TX_ID`,`BRANCH_QUALIFIER`)) ENGINE=InnoDB DEFAULT CHARSET=utf8

如果表名称不对,启动过程会报错,这时,对数据表做相应调整即可。


6.发布服务(重点)

6.1 dubbo接口
 /**  * @author binghe  * 资产相关的业务发布Dubbo服务  */public interface AssetCardService {     /**     * 测试预保存资产(状态为待确认)     */    @Compensable    int testSaveAssetCard(AssetCardModel model);     /**     * 确认保存资产到mysql(状态为正常)     */    int confirmMysqlSaveAssetCard(AssetCardModel model);     /**     * 取消保存资产到msyql(更新状态为删除)     */    int cancelMysqlSaveAssetCard(AssetCardModel model);     /**     * 预保存资产到mongo(状态为待确认)     */    @Compensable    void processMongo(AssetCardModel model);     /**     * 确认保存资产到mongo(状态为正常)     */    void confirmMongoSaveAssetCard(AssetCardModel model);     /**     * 取消保存资产到mongo(更新状态为删除)     */    void cancelMongoSaveAssetCard(AssetCardModel model); }

需要注意的点:1.对外提供服务的接口必须有@Compensable注解;2.对应的confirm与cancel方法必须声明为接口,不能声明为private,即使是public也不行,必须有接口。

6.2 dubbo接口实现类
/*** @author binghe* 资产相关的业务发布Dubbo服务的实现*/@Service@Componentpublic class AssetCardServiceImpl implements AssetCardService{    @Override  @Compensable(confirmMethod = "confirmMysqlSaveAssetCard", cancelMethod = "cancelMysqlSaveAssetCard", transactionContextEditor = DubboTransactionContextEditor.class)  @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })  public int testSaveAssetCard(AssetCardModel model){       // 保存mysql,data状态为-1      model.setDataStatus(-1);      assetCardDao.insert(model);        // mongo处理      assetCardService.processMongo(model);       return model.getId();  }   @Override  public int confirmMysqlSaveAssetCard(AssetCardModel model){      System.out.println("============================================================================");      System.out.println("=================mysql:confirm");      System.out.println("============================================================================");       // 更新mysql data_status为0      model.setDataStatus(0);      assetCardDao.updateByPrimaryKey(model);       return model.getId();  }   @Override  public int cancelMysqlSaveAssetCard(AssetCardModel model){      System.out.println("============================================================================");      System.out.println("=================mysql:cancel");      System.out.println("============================================================================");       // 更新mysql data_status为-1      model.setDataStatus(-1);      assetCardDao.updateByPrimaryKey(model);       return model.getId();  }   @Compensable(confirmMethod = "confirmMongoSaveAssetCard", cancelMethod = "cancelMongoSaveAssetCard", transactionContextEditor = DubboTransactionContextEditor.class)  @Override  public void processMongo(AssetCardModel model) {       // 保存mongo,data_statu为-1      model.setDataStatus(-1);      assetCardDaoWrapper.saveMongo(model);  }   @Override  public void confirmMongoSaveAssetCard(AssetCardModel model){      System.out.println("============================================================================");      System.out.println("=================mongo:confirm");      System.out.println("============================================================================");       // 更新mongo data_status为0      model.setDataStatus(0);      assetCardDaoWrapper.updateMongo(model);  }   @Override  public void cancelMongoSaveAssetCard(AssetCardModel model){      System.out.println("============================================================================");      System.out.println("=================mongo:cancel");      System.out.println("============================================================================");       // 更新mongo data_status为-1      model.setDataStatus(-1);      assetCardDao.updateByPrimaryKey(model);      assetCardDaoWrapper.updateMongo(model);  }}

注意点:

1.对外提供服务的接口必须有@Compensable注解,同时必须有confirmMethod、cancelMethod参数的配置,同时dubbo接口额外增加 "transactionContextEditor = DubboTransactionContextEditor.class"这个配置;

相关推荐

详解DNFSB2毒王的各种改动以及大概的加点框架

首先附上改动部分,然后逐项分析第一个,毒攻掌握技能意思是力量智力差距超过15%的话差距会被强行缩小到15%,差距不到15%则无效。举例:2000力量,1650智力,2000*0.85=1700,则智力...

通篇干货!纵观 PolarDB-X 并行计算框架

作者:玄弟七锋PolarDB-X面向HTAP的混合执行器一文详细说明了PolarDB-X执行器设计的初衷,其初衷一直是致力于为PolarDB-X注入并行计算的能力,兼顾TP和AP场景,逐渐...

字节新推理模型逆袭DeepSeek,200B参数战胜671B,豆包史诗级加强

梦晨发自凹非寺量子位|公众号QbitAI字节最新深度思考模型,在数学、代码等多项推理任务中超过DeepSeek-R1了?而且参数规模更小。同样是MoE架构,字节新模型Seed-Thinkin...

阿里智能化研发起飞!RTP-LLM 实现 Cursor AI 1000 token/s 推理技术揭秘

作者|赵骁勇阿里巴巴智能引擎事业部审校|刘侃,KittyRTP-LLM是阿里巴巴大模型预测团队开发的高性能LLM推理加速引擎。它在阿里巴巴集团内广泛应用,支撑着淘宝、天猫、高德、饿...

多功能高校校园小程序/校园生活娱乐社交管理小程序/校园系统源码

校园系统通常是为学校、学生和教职工提供便捷的数字化管理工具。综合性社交大学校园小程序源码:同城校园小程序-大学校园圈子创业分享,校园趣事,同校跑腿交友综合性论坛。小程序系统基于TP6+Uni-app...

婚恋交友系统nuiAPP前端解决上传视频模糊的问题

婚恋交友系统-打造您的专属婚恋交友平台系统基于TP6+Uni-app框架开发;客户移动端采用uni-app开发,管理后台TH6开发支持微信公众号端、微信小程序端、H5端、PC端多端账号同步,可快速打包...

已节省数百万GPU小时!字节再砍MoE训练成本,核心代码全开源

COMET团队投稿量子位|公众号QbitAI字节对MoE模型训练成本再砍一刀,成本可节省40%!刚刚,豆包大模型团队在GitHub上开源了叫做COMET的MoE优化技术。COMET已应用于字节...

通用电气完成XA102发动机详细设计审查 将为第六代战斗机提供动力

2025年2月19日,美国通用电气航空航天公司(隶属于通用电气公司)宣布,已经完成了“下一代自适应推进系统”(NGAP)计划下提供的XA102自适应变循环发动机的详细设计审查阶段。XA102是通用电气...

tpxm-19双相钢材质(双相钢f60材质)

TPXM-19双相钢是一种特殊的钢材,其独特的化学成分、机械性能以及广泛的应用场景使其在各行业中占有独特的地位。以下是对TPXM-19双相钢的详细介绍。**化学成分**TPXM-19双相钢的主要化学成...

thinkphp6里怎么给layui数据表格输送数据接口

layui官网已经下架了,但是产品还是可以使用。今天一个朋友问我怎么给layui数据表格发送数据接口,当然他是学前端的,后端不怎么懂,自学了tp框架问我怎么调用。其实官方文档上就有相应的数据格式,js...

完美可用的全媒体广告精准营销服务平台PHP源码

今天测试了一套php开发的企业网站展示平台,还是非常不错的,下面来给大家说一下这套系统。1、系统架构这是一套基于ThinkPHP框架开发的HTML5响应式全媒体广告精准营销服务平台PHP源码。现在基于...

一对一源码开发,九大方面完善基础架构

以往的直播大多数都是一对多进行直播社交,弊端在于不能满足到每个用户的需求,会降低软件的体验感。伴随着用户需求量的增加,一对一直播源码开始出现。一个完整的一对一直播流程即主播发起直播→观看进入房间观看→...

Int J Biol Macromol .|交联酶聚集体在分级共价有机骨架上的固定化:用于卤代醇不对称合成的高稳定酶纳米反应器

大家好,今天推送的文章发表在InternationalJournalofBiologicalMacromolecules上的“Immobilizationofcross-linkeden...

【推荐】一款开源免费的 ChatGPT 聊天管理系统,支持PC、H5等多端

如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍GPTCMS是一款开源且免费(基于GPL-3.0协议开源)的ChatGPT聊天管理系统,它基于先进的GPT...

高性能计算(HPC)分布式训练:训练框架、混合精度、计算图优化

在深度学习模型愈发庞大的今天,分布式训练、高效计算和资源优化已成为AI开发者的必修课。本文将从数据并行vs模型并行、主流训练框架(如PyTorchDDP、DeepSpeed)、混合精度训练(...

取消回复欢迎 发表评论: