104:基于LCN解决分布式事务与源码分析
1 LCN解决分布式事务问题演示
课题内容
- 如何理解2PC两阶段提交协议
- 基于LCN解决分布式事务原理
- SpringCloud整合LCN解决分布式事务问题
- LCN解决分布式事务源码分析
演示RPC远程通讯产生分布式事务问题
2 如何理解2PC两阶段提交协议
zk集群中,所有的写的请求统一交给leader实现,leader写完数据后,再同步给每个从节点,每个节点之间的数据同步需要保证数据一致性的问题。
zk将数据写入完毕后如何将数据同步给从节点保证数据一致性?
- 第一阶段 准备阶段 zk领导会给每个从节点发一个通知,是否可以同步该数据,所有的从节点回复给zk领导可以同步数据;
- 第二阶段 zk领导收到zk从节点回复的可以同步数据,再直接将数据同步给每个从节点。
两阶段提交协议可以理解为2PC,也就是分为参与者和协调者,协调者会通过两次阶段实现数据的最终一致性。
2PC和3PC的区别就是解决参与者超时的问题和多加了一层询问保证传输数据的可靠性。
3 LCN基本的框架的概述
TX-LCN分布式事务框架
LCN并不生产事务,LCN只是本地事务的协调工。
LCN模式解决分布式事务实现的原理
- 发起方和参与方在项目启动的时候必须和全局协调者一直保持长连接;
- 发起方向LCN协调者申请一个事务分组id;
- 发起方在调用参与方接口的时候,重写feign客户端,在请求头中传递该事务分组id;
- 参与方获取到请求头中有传递对应的事务分组id,当前业务执行完毕之后不会提交事务,采用jdbc假关闭连接;
- 发起方如果产生了回滚或者提交的话,都会将该结果告诉给协调者,协调者再将该结果群发给所有的参与者。
4 LCN客户端如何整合LCN全局协调者
lcn官网下载项目tx-lcn-5.0.2.RELEASE
数据库中建库建表(tx-mamager.sql) 启动本地redis,启动项目TMApplication
7970端口号 后台管理平台
8070端口号 发起方、端口放连接lcn通讯
整合LCN全局协调者
1.引入依赖
<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>
2.application.yml中增加配置
tx-lcn:
client:
manager-address: 127.0.0.1:8070
logger:
enabled: true
3.注解
项目启动类增加注解@EnableDistributedTransaction
服务实现类方法新增注解@LcnTransaction(注意原@Transactional仍要保留)
测试效果
5 TransactionAspect切面类源码分析
1、判断方法上是否有加上@LcnTransaction,如果有该注解走TransactionAspect切面类;
2、判断当前线程缓存中是否有事务分组id,如果没有则为发起方,如果有则为参与方;
3、随机创建分组id,将该分组id注册到协调者中,同时本地Threadlocal缓存该事务分组id;
4、创建完事务分组id之后,执行目标方法,如果执行失败catch捕获异常,将事务状态改为0(表示失败)再通知给LCN协调者;
5、订单服务调用派单服务,重写RequestInterceptor Feign客户端拦截器,将该事务分组id设置到请求头中;
6 参与方如何加入LCN全局协调者
6、SpringTracingApplier拦截器在派单服务进入请求之前拦截,从请求头中获取事务分组id,如果有则放入到缓存中;
7、派单服务上也有@LcnTransaction注解,被拦截进入到切面类,根据当前线程获取到事务分组id(即可判断为参与方);
8、参与方拿到threadLocal把当前线程的jdbc连接设置代理资源,事务不会提交也不会回滚(等待LCN通知),实现假关闭;
一个请求对应一个线程,整个流程都是一个线程处理。
7 发起方如何通知全局回滚还是提交
9、参与方执行事务成功/失败,变更当前线程事务状态sysTransactionState(成功1失败0),业务执行完毕把事务状态信息通知给协调者。由于参与方与LCN协调者一直保持长连接,LCN协调者收到事务状态信息再通知到参与方。
8 A调用B,B调用C如何实现全局回滚
A调用B,B调用C,C调用D如何实现全局回滚?
A为发起方,BCD都为参与方,共用同一个全局分组id,参与方没有通知给协调者回滚权限。如果C调用D成功,B调用C后面代码执行出问题,将异常抛给A(不断往前抛),A服务捕获到异常通知给协调者,协调者再通知给所有参与方实现全局回滚。