目录
分布式事务tx-lcn
tc-lcn官网:https://www.txlcn.org/zh-cn/index.html
一、分布式事务介绍
目前分布式事务存在两大理论依据:CAP定律 BASE理论。
CAP定律:指的是在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
BASE理论:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
二、tx-lcn框架介绍
1、版本介绍:LCN框架在2017年6月份发布第一个版本,从开始的1.0,已经发展到了5.0版本。5.0以后由于框架兼容了LCN、TCC、TXC三种事务模式,为了避免区分LCN模式,特此将LCN分布式事务改名为TX-LCN分布式事务框架。
2、框架定位:本身并不操作事务,而是基于对本地事务的协调从而达到事务一致性的效果。
3、tx-lcn原理:TX-LCN由TxClient、TxManager两大模块组成。TxManager作为分布式事务的控制方。事务发起方或者参与反都由TxClient端来控制。
①事务发起方,创建事务组到TxManager;参与方分别加入事务组;
②参与方通知TxManager都准备好了,再一次通知参与方执行事务。按照执行顺序通知。
③TxManager将事务结果返回给事务发起方。
原理图如下:
4、tx-lcn之lcn、tcc、txc模式对比
lcn模式:①对代码的嵌入性为低。
②事务的提交和回滚基于本地事务方控制,对数据一致性有较高的保障。
③缺陷:代理的连接需要事务发起方一共释放连接,增加了连接占用的事件。
tcc模式:
原理:不依赖资源管理器对XA的支持,而是通过对业务逻辑的调度来实现分布式事务,共分为三步:Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务;
①对代码的嵌入性高,要求每个业务需要写三种步骤的操作;
②对有无本地事务控制都可以支持,使用面广。
③数据一致性控制几乎完全由开发者控制,对业务开发难度要求高。
txc模式:
原理:在执行SQL之前,先查询SQL的影响数据,然后保存这些信息和创建锁。当需要回滚的时候,就采用这些记录数据回滚数据库,目前锁实现依赖redis分布式锁控制。
①同样对代码的嵌入性低。
②仅限于对支持SQL方式的模块支持。
③由于每次执行SQL之前需要先查询影响数据,因此相比LCN模式消耗资源与时间要多。
④不会占用数据库的连接资源。
三、Tx-LCN之lcn模式实践demo
1、demo环境
jdk1.8 、springboot2.0.6、springcloud Finchley.SR1、redis3.2.100 、txlcn-tm 5.0.2.RELEASE
2、搭建说明
需先搭建tx-manager服务,然后其他服务使用。
springcloud环境之前已经搭建好,这里不再阐述。
3、搭建tx-manager服务
①建立数据库,库名为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 DEFAULT NULL,
`unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`transaction_state` tinyint(4) DEFAULT NULL,
`registrar` tinyint(4) DEFAULT NULL,
`remark` varchar(4096) COLLATE utf8mb4_general_ci DEFAULT NULL,
`ex_state` tinyint(4) DEFAULT NULL COMMENT '0 未解决 1已解决',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
②创建服务模块,然后导报
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tm</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
③在启动类上添加注解
@EnableTransactionManagerServer
④配置文件application.properties
根据自己的实际情况修改,更多配置请参考官网http://www.txlcn.org/zh-cn/docs/setting/manager.html
#指定注册中心地址
eureka.client.serviceUrl.defaultZone= http://localhost:1010/eureka/
eureka.instance.instance-id=tx-manager
eureka.instance.prefer-ip-address=true
#服务端口
server.port=2030
#服务名
spring.application.name=tx-manager
#数据库配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
#mybatis配置
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true
#TxManager配置
# TxManager Host Ip
tx-lcn.manager.host=127.0.0.1
# TxClient连接请求端口
tx-lcn.manager.port=8070
# 心跳检测时间(ms) 默认为 300000
tx-lcn.manager.heart-time=15000
# 分布式事务执行总时间 默认为36000
tx-lcn.manager.dtx-time=30000
#参数延迟删除时间单位ms
tx-lcn.message.netty.attr-delay-time=30000
tx-lcn.manager.concurrent-level=128
# TM后台登陆密码,默认值为codingapi
tx-lcn.manager.admin-key=codingapi
# 开启日志
tx-lcn.logger.enabled=true
logging.level.com.codingapi=debug
#redis 主机
spring.redis.host=127.0.0.1
#redis 端口
spring.redis.port=6379
#redis 密码
spring.redis.password=
⑤测试服务
安装完成,启动服务,访问tx-manager管理后台:http://localhost:7970/admin/index.html#/login
类似注册中心,可以看到哪些服务需要做事务处理的。可以看到配置的信息,还有异常记录和错误日志。
登录的默认密码为codingapi
4、使用分布式事务
配置tc-client,就是自己需要使用的服务。注意:A服务调用B服务,那个A\B服务都需要做下面的配置。
①、导包
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-txmsg-netty</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
②、开启微服务事务
启动类上加入注解 @EnableDistributedTransaction
③、application.properties配置
添加tm-manager的服务地址
#默认是本机的8070端口,可以不写,可根据需要修改
tx-lcn.client.manager-address=127.0.0.1:8070
④、服务层添加注解
如:A服务调用B服务
a服务:
service层的方法上:@LcnTransaction @Transactional
//利用feign添加部门信息
@Override
@LcnTransaction //lcn的事务注解
@Transactional //本地事务注解
public ResultVo addDepartment(Department department) {
User user = new User("大娃","123456",26);
userMapper.addUser(user); //给本地添加数据
systemManageClient.addDepartment(department); //调取其他服务添加数据
return ResultVo.ok();
}
b服务:
lcn事务配饰说明:
RQUIRED:如果有事务就把这个操作加入事务中,如果没有事务就另外新建一个事务。如:增删改操作。
SUPPORTS:是有事务就把操作加入事务,没有事务也能脱离事务独立运行。如查询操作。
//添加部门
@Override
@LcnTransaction(propagation = DTXPropagation.SUPPORTS)
@Transactional
public void addDepartment(Department department) {
//System.out.println(1/0);//测试分布式事务,发生异常后,user服务还能不能添加进去
departmentMapper.addDepartment(department);
}
注意:如果通过feign 调用时,feign注解中加了fallbackFactory =xxx.class的话;在Fallback方法里面加上这个
DTXUserControls.rollbackGroup(TracingContext.tracing().groupId());
@Component
public class SystemManageFallback implements SystemManageClient {
@Override
public ResultVo addDepartment(Department department) {
DTXUserControls.rollbackGroup(TracingContext.tracing().groupId());
return ResultVo.fail("添加部门信息失败了");
}
}
测试:当B服务失败后,发起方A的数据也会回滚。创建成功。