目录
TX-LCN 分布式事务框架
TX-LCN 分布式事务框架
随着互联化的蔓延, 各种项目都逐渐向分布式服务做转换. 如今微服务已经普遍存在, 本地事务已经无法满足分布式的要求, 由此分布式事务问题诞生. 分布式事务被称为世界性的难题, 目前分布式事务存在两大理论依据: CAP 定律 BASE 理论.
官网地址: https://www.txlcn.org/zh-cn/
GitHun:https://github.com/yizhishang/tx-lcn/
在一个分布式系统下存在多个模块协调来完成一次业务. 那么就存在一次业务事务下可能横跨多种数据源节点的可能. TX-LCN 将可以解决这样的问题.
例如存在服务模块 A ,B, C.A 模块是 MySQL 作为数据源的服务, B 模块是基于 Redis 作为数据源的服务, C 模块是基于 mongo 作为数据源的服务. 若需要解决他们的事务一致性就需要针对不同的节点采用不同的方案, 并且统一协调完成分布式事务的处理.
方案:
若采用 TX-LCN 分布式事务框架, 则可以将 A 模块采用 LCN 模式, B/C 采用 TCC 模式就能完美解决.
TX-LCN 主要有两个模块, Tx-Client(TC) Tx-Manager(TM). TC 作为微服务下的依赖, TM 是独立的服务.
安装 TM 需要依赖的中间件: JRE1.8+, Mysql5.6+, Redis3.2+
如果需要手动编译源码, 还需要 Git, Maven, JDK1.8+
创建 MySQL 数据库, 名称为: tx-manager
创建数据表
- CREATE TABLE `t_tx_exception` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT,
- `group_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
- `unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
- `mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
- `transaction_state` tinyint(4) NULL DEFAULT NULL,
- `registrar` tinyint(4) NULL DEFAULT NULL,
- `remark` varchar(4096) NULL DEFAULT NULL,
- `ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 未解决 1 已解决',
- `create_time` datetime(0) NULL DEFAULT NULL,
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
TM 下载与配置
从历史版本 TM 下载 https://bbs.txlcn.org/viewtopic.php?id=44 找到 5.0.2.RELEASE 的 TM, 下载.
修改配置信息
- spring.application.name=tx-manager
- server.port=7970
- spring.datasource.driver-class-name=com.MySQL.jdbc.Driver
- spring.datasource.url=jdbc:MySQL://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8
- spring.datasource.username=root
- spring.datasource.password=root
- mybatis.configuration.map-Underscore-to-camel-case=true
- mybatis.configuration.use-generated-keys=true
- # TxManager Host Ip
- tx-lcn.manager.host=127.0.0.1
- # TxClient 连接请求端口
- tx-lcn.manager.port=8070
- # 心跳检测时间 (ms)
- tx-lcn.manager.heart-time=15000
- # 分布式事务执行总时间
- tx-lcn.manager.dtx-time=30000
- # 参数延迟删除时间单位 ms
- tx-lcn.message.netty.attr-delay-time=10000
- tx-lcn.manager.concurrent-level=128
- # TM 后台登陆密码, 默认值为 codingapi
- tx-lcn.manager.admin-key=123456
- logging.level.com.codingapi=debug
- #Redis 主机
- spring.Redis.host=127.0.0.1
- #Redis 端口
- spring.Redis.port=6379
- #Redis 密码
- spring.Redis.password=
- # 开启日志, 默认为 false
- tx-lcn.logger.enabled=true
- tx-lcn.logger.driver-class-name=${
- spring.datasource.driver-class-name
- }
- tx-lcn.logger.jdbc-url=${
- spring.datasource.url
- }
- tx-lcn.logger.username=${
- spring.datasource.username
- }
- tx-lcn.logger.password=${
- spring.datasource.password
- }
- # 给出信息都是默认值
关于详细配置说明见 TM 配置
application.properties 加载顺序如下:
0, 命令行启动参数指定
- ,file:./config/(当前 jar 目录下的 config 目录)
- ,file:./(当前 jar 目录)
- ,classpath:/config/(classpath 下的 config 目录)
- ,classpath:/(classpath 根目录)
发布的二进制可执行 Jar 包含一个默认配置文件 (也就是 4), 可按需要覆盖默认配置
把 txlcn-tm 的 pom 打包方式修改成
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
手动编译 TM, 简单指引
- # Git clone https://github.com/codingapi/tx-lcn.git & cd txlcn-tm
- # mvn clean package '-Dmaven.test.skip=true'
target 文件夹下, 即为 Ttxlcn-tm-5.0.2.RELEASE.jar
TC 微服务模块
服务 A 作为 DTX 发起方, 远程调用服务 B
工程说明
finchley 父项目主要进行依赖管理
common-config 可存方公共配置级工具
common-eureka 服务注册中心
gateway-zuul 网关
user-server 服务 1
money-server 服务 2
忽略其他工程搭建步骤.
事务操作实例
user-server 提供远程服务, money-server 通过 fegin 发现服务调用进行事务回滚.
这两个服务需要加入依赖, 如下:
- <!-- springcloud 分布式事物 -->
- <dependency>
- <groupId>com.codingapi.txlcn</groupId>
- <artifactId>txlcn-tc</artifactId>
- <version>5.0.2.RELEASE</version>
- <exclusions>
- <exclusion>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>com.codingapi.txlcn</groupId>
- <artifactId>txlcn-txmsg-netty</artifactId>
- <version>5.0.2.RELEASE</version>
- <exclusions>
- <exclusion>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
依赖最好跟随 TM 管理器版本, 方式出现奇怪问题.
两个工程的启动类使用该 @EnableDistributedTransaction 标记启动分布式事务.
两个工程 properties 需要加入事务管理器监控地址, 如下:
- # 该配置根据 TM 打包时的配置进行
- tx-lcn.client.manager-address=127.0.0.1:8070
在 user-server 和 money-server 插入数据, server 实例:
- /**
- * user-server
- * @Auhotr:SimpleWu
- * @TxTransaction 使用该注解启动分布式事务
- * @Transactional 同时使用 spring 事务开启本地事务
- * 插入一个用户
- */
- @Override
- @TxTransaction
- @Transactional
- public int insertUser(Map<String, Object> map) {
- userServerMapper.insert(map);
- return "insertUser success";
- }
- //fegin 调用 user-server 服务
- @Autowired
- private UserFegin userFegin;
- // 对 money 表操作 mapper
- @Autowired
- private MoneyServerMapper moneyServerMapper;
- /**
- * user-server
- * @Auhotr:SimpleWu
- * @TxTransaction 使用该注解启动分布式事务
- * @Transactional 同时使用 spring 事务开启本地事务
- * 插入一个用户
- */
- @Override
- @TxTransaction
- @Transactional
- public String insert() {
- String userId = UUID.randomUUID().toString();
- Map<String,Object> param = new HashMap<>();
- param.put("ID",userId);
- param.put("USER_ID",userId);
- param.put("MONEY",100);
- param.put("USERPASS","12321321");
- // 先调用远程服务测试事务回滚
- System.out.println( userFegin.hello("张三","12321321",userId));
- int i = 0 / 0;
- moneyServerMapper.insert(param);
- return "success" + param;
- }
启动顺序:
部署 Redis
部署 TM 的 Jar 包
部署 Eureka 服务注册中心
部署 user-server 服务
部署 money-server 服务
忽略网关等.....
访问 money-server 服务 :http://localhost:13000/hello 调用 insert();
int i = 0 / 0;
该行代码发生异常, UserFegin 为 user-server 远程放服务调用后打印 "insertUser success" 代表调用成功, 如果分布式事务没有效果, 那么遇见该异常远程方不会进行回滚.
在本次测试是回滚成功的, 就不贴图了, 亲自尝试才能体会到, 那种感觉.
然后删除 money-server 中删除 int i = 0 / 0; 重新启动.
再次调用 http://localhost:13000/hello 调用 insert(), 成功插入两条数据.
访问: http://localhost:7970 进入 TxManager 系统后台, 登录密码是我们设置的 123456. 里面可以看到配置信息, 以及异常信息日志, 系统日志.
该篇案例源代码与工具见: https://github.com/450255266/open-doubi
来源: https://www.cnblogs.com/SimpleWu/p/10922654.html