目录
1.前序
现如今,分布式框架纵横的大潮下,对于分布式的相关应用和技术的了解和使用也是必不可少的。最显著的几个技术点,我认为大概就是分布式事务,分布式锁,分布式高并发处理等等。而今天,我这边主要和大家分享一下,个人通过实践操作在分布式事务操作方面的过程。
2.过程
2.1 TX-LCN框架介绍
tx-lcn框架官网地址:http://www.txlcn.org/zh-cn/docs/preface.html
相关介绍,官网有详细信息。下面,我就其主要流程原理做下简要说明。
该框架的工作原理流程内容主要就是如图所示。个人简单总结一下:
TX-LCN框架中,为我们提供了一个核心中间件Tx-Manager,它是一个事务管理器。而我们的微服务或项目(会加入框架依赖包)作为Tx-Client端,在分布式服务调用过程中,从请求发起到结束,请求链路中,请求发起方或参与方与Tx-Manager的互动都由Tx-Client控制,所有的事务都交由此事务管理器Tx-Manager处理。如图工作流程:
①一个请求发起
②会先去Tx-Manager那里创建一个事务组
③再调用微服务A接口,调用的同时也会去申请加入步骤②中创建的事务组
④然后调用微服务B接口,也会申请加入事务组
⑤链路中可添加更多的微服务,每个服务调用都会加入事务组
⑥待请求结束后,会返回到请求发起方。再由请求发起方,通知Tx-Manager事务组。
⑦Tx-Manager开始对事务组中的每一个事务单元进行处理,并将处理结果记录。
⑧最后对每一个事务单元的处理结果进行整合,并决定整体事务是提交或是回滚,将最终结果返回给请求发起方。
2.2 环境搭建
2.2.1 开发环境
我本次的项目框架使用的是:SpringCloud版本Finchley.SR4,SpringBoot版本2.0.5.RELEASE,Redis
坑点:原本环境我是使用的稳定版本Dalston SR1和1.5.9.RELEASE,但是与TX-LCN框架整合后多次测试时启动报错。尝试更替依赖等,尝试很久无果,后考虑是环境低版本导致。所以后来切换到了高版本,果然就可以正常启动了。
2.2.2 数据库环境
- 创建MySQL数据库, 名称为: tx-manager
- 创建数据表,sql语句如下:
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;
此表是用来记录事务组处理事务单元的信息记录。
2.2.3 Tx-Manager下载和配置
我是直接使用的官网的SpringCloud Demo中的TM(Tx-Manager简称)。GitHub下载地址:https://github.com/codingapi/txlcn-demo ;可以只下载txlcn-demo-common和txlcn-demo-tm,其他的为Demo代码,也可以下载参考。
下载完成后,引入自己的IDEA工具。结构如下:
这里我需要说明一下,为什么我引入了txlcn-demo-common。其实可以不用引入,但这个是Demo中的通用依赖包,里面有一些共用依赖,我这边当时单独引入txlcn-demo-tm启动时有报错,应该是包依赖问题,没有自行添加依赖测试,有兴趣的可以自己添加依赖后单独启动试试。所以我这边就将两个子项目一起引入了,是可以正常启动的。
引入上面的项目后,需要修改两个地方:
①在启动类添加注解@EnableTransactionManagerServer
package org.txlcn.tm;
import com.codingapi.txlcn.tm.config.EnableTransactionManagerServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableTransactionManagerServer
public class TransactionManagerApplication {
public static void main(String[] args) {
SpringApplication.run(TransactionManagerApplication.class, args);
}
}
②修改application.properties文件,配置如下:
##################
# 这个是启动本服务的配置文件,其它的application-xxx.properties 是开发者的个性化配置,不用关心。
# 你可以在 https://txlcn.org/zh-cn/docs/setting/manager.html 看到所有的个性化配置
#################
spring.application.name=TransactionManager
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&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
# 数据库方言
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
# 第一次运行可以设置为: create, 为TM创建持久化数据库表
spring.jpa.hibernate.ddl-auto=validate
# TM监听IP. 默认为 127.0.0.1
tx-lcn.manager.host=127.0.0.1
# TM监听Socket端口. 默认为 ${server.port} - 100
tx-lcn.manager.port=8070
# 心跳检测时间(ms). 默认为 300000
tx-lcn.manager.heart-time=300000
# 分布式事务执行总时间(ms). 默认为36000
tx-lcn.manager.dtx-time=8000
# 参数延迟删除时间单位ms 默认为dtx-time值
tx-lcn.message.netty.attr-delay-time=${tx-lcn.manager.dtx-time}
# 事务处理并发等级. 默认为机器逻辑核心数5倍
tx-lcn.manager.concurrent-level=160
# TM后台登陆密码,默认值为codingapi
tx-lcn.manager.admin-key=codingapi
# 分布式事务锁超时时间 默认为-1,当-1时会用tx-lcn.manager.dtx-time的时间
tx-lcn.manager.dtx-lock-time=${tx-lcn.manager.dtx-time}
# 雪花算法的sequence位长度,默认为12位.
tx-lcn.manager.seq-len=12
# 异常回调开关。开启时请制定ex-url
tx-lcn.manager.ex-url-enabled=false
# 事务异常通知(任何http协议地址。未指定协议时,为TM提供内置功能接口)。默认是邮件通知
tx-lcn.manager.ex-url=/provider/email-to/
# 开启日志,默认为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}
# redis 的设置信息. 线上请用Redis Cluster
#spring.redis.host=127.0.0.1
#spring.redis.port=6379
#以debug级别,可以看到事务组处理时的一些日志情况
logging.level.root=debug
pom文件无需改动。启动redis server端后,如此TM就可以启动了。启动成功后,通过浏览器http://localhost:7970/admin/index.html#/login出现登录界面后,就说明TM已经正常部署好了。通过初始密码codingapi进入:
2.2.4 微服务启动
在自己的微服务项目中,首先在pom.xml文件中,添加TX-LCN框架依赖的核心包。如下:
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tc</artifactId>
<version>5.0.2.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-txmsg-netty</artifactId>
<version>5.0.2.RELEASE</version>
<optional>true</optional>
</dependency>
其次,在项目的主启动类加上@EnableDistributedTransaction注解。每一个需要使用到分布式事务控制的项目都需要加上。
最后,在代码上,添加上事务框架的注解@LcnTransaction,@Transactional,如下:
@Override
@LcnTransaction//分布式事务
@Transactional //本地事务
public int updateUserInfo() {
//先调用另一个服务的update操作
User user1 = new User();
user1.setId(1);
user1.setAge(30); //原数据21
int result1 = userService.updateUser(user1);
log.info("第一个服务调用完成,result1="+result1);
if(1<2){
throw new RuntimeException("我是测试分布式事务的异常。。。。");
}
//再调用本服务update操作
User otherUser = new User();
otherUser.setId(2);
otherUser.setAge(33);//原数据25
int result = userMapper.updateById(otherUser);
log.info("来自11000的用户更新结果为:"+result);
return result;
}
至此,整个框架整合基本完成。现在可以启动我们的项目,测试分布式事务是否有效啦。测试结果,我这边就不展示了,亲测有效,因为异常,会回滚第一个写操作的事务。
3.总结
TX-LCN分布式事务框架也分多种事务模式,其原理也是基于XA两端提交,TCC模式等实现。本次是分享是使用的LCN模式,虽然实现流程基本了解,但还没有分析过其源码。因为时间问题,其实最后还有一个疑问暂未解决:
在发生异常,分布式事务回滚后,数据表t_tx_exception中应该有写入相关记录,但是我在实践过程中却没有插入任何信息
学习分享的同时,也是相互取经的过程。希望有知道的大神或是朋友能够不吝赐教,本人也会后续跟进更新。