Java详细分析LCN框架分布式事务

 更新时间:2022年07月28日 15:38:38   作者:kaico2018  
这篇文章主要介绍了Java LCN框架分布式事务,分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上

2PC两阶段提交协议

分布式事务通常采用2PC协议,全称Two Phase Commitment Protocol。该协议主要为了解决在分布式数据库场景下,所有节点间数据一致性的问题。分布式事务通过2PC协议将提交分成两个阶段:

  • 阶段一为准备(prepare)阶段。即所有的参与者准备执行事务并锁住需要的资源。参与者ready时,向transaction manager报告已准备就绪。
  • 阶段二为提交阶段(commit)。当transaction manager确认所有参与者都ready后,向所有参与者发送commit命令。

2PC和3PC的区别就是解决参与者超时的问题和多加了一层询问,保证数据的传输可靠性。

LCN

LCN并不生产事务,LCN只是本地事务的协调工,TX-LCN定位于一款事务协调性框架,框架其本身并不操作事务,而是基于对事务的协调从而达到事务一致性的效果。

参考文档:https://www.codingapi.com/docs/txlcn-preface/

LCN基本实现原理

  • 发起方与参与方都与我们的 LCN 管理器一直保持长连接;
  • 发起方在调用接口之前,先向 LCN 管理器申请一个全局的事务分组id;
  • 发起方调用接口的时候在请求头中传递事务分组id;
  • 参与方获取到请求头中有事务分组的id的,则当前业务逻辑执行完实现假关闭,不会提交或者回滚当前的事务。
  • 发起方调用完接口后,如果出现异常的情况下,在通知给事务协调者回滚事务,这时候事务协调则告诉给参与方回滚当前的事务。

搭建全局协调者

1、在github上面下载 Lcn 源代码

仓库地址:https://github.com/codingapi/tx-lcn,注意下载版本。

2、将项目导入idea中,启动对应的项目

修改对应的配置文件:

spring.application.name=TransactionManager
server.port=7970
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://www.kaicostudy.com:3306/transaction_lcn?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456

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
# 开启日志
tx-lcn.logger.enabled=true
logging.level.com.codingapi=debug

#redis 连接信息
spring.redis.host=www.kaicostudy.com
spring.redis.port=6379
redis\u5BC6\u7801
#spring.redis.password=

将项目中提供的SQL语句在数据库中执行,创建对应的表。

请求路径:http://127.0.0.1:7970/admin/index.html

默认登录密码:codingapi

登录成功页面

端口介绍:

8070:TM事务消息端口

7970:后台管理页面登录页面

使用LCN解决分布式事务问题

在分布式系统A系统调用B系统服务接口的时候时候,两个服务的都需要使用 LCN 来控制分布式事务。

使用步骤:

1、引入lcn 相关的maven依赖

<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、yml 配置文件增加 lcn 的配置

tx-lcn:
  client:
    manager-address: www.kaicostudy.com:8070
  logger:
    enabled: true

3、使用

springboot项目主类上加上注解:@EnableDistributedTransaction

参与方与发起方都要加上该注解

@LcnTransaction

@Transactional

调用案例:

A服务的方法,需要去调用B服务方法

@Service
public class ServiceA {
    @Autowired
    private ValueDao valueDao; //本地db操作
    @Autowired
    private ServiceB serviceB;//远程B模块业务
    @LcnTransaction //分布式事务注解
    @Transactional //本地事务注解
    public String execute(String value) throws BusinessException {
        // step1. call remote service B
        String result = serviceB.rpc(value);  // (1)
        // step2. local store operate. DTX commit if save success, rollback if not.
        valueDao.save(value);  // (2)
        valueDao.saveBackup(value);  // (3)
        return result + " > " + "ok-A";
    }
}

B服务的方法,被A服务的方法调用

@Service
public class ServiceB {
    @Autowired
    private ValueDao valueDao; //本地db操作
    @LcnTransaction //分布式事务注解
    @Transactional  //本地事务注解
    public String rpc(String value) throws BusinessException {
        valueDao.save(value);  // (4)
        valueDao.saveBackup(value);  // (5)
        return "ok-B";
    }
}

源码分析

一个请求一个线程

代码执行逻辑:

1、判断方法是否有加上@L cnTransaction, 如果有加上该注解则直接会走 切面类 TransactionAspect

2、判断当前线程缓存中是否有事务分组id,如果没有缓存则是为发起方,如果有缓存则是为参与方

3、随机的创建分组的id,将该分组id注册到协调者中。

4、本地 threadLock 缓存该事务分组id

5、A服务(发起方)调用B(参与方)服务的接口,重写了 RequestInterceptor(该接口是feign框架提供的拦截器,基本上每个rpc框架都会提供类似的拦截器) feign 客户端,将该事务分组id设置到请求中

6、执行到B服务接口,Spring TracingApplier实现,在请求之前拦截,从请求头中获取事务分组id,放入到当前线程缓存中

7、B服务接口走到aop里面代码时,会先判断是发起方还是参与方。

8、从缓存中获取该事务分组id,当前派单服务则是为参与方,在告诉给协调者加入该事务分组。.

Lcn 如何判断自己是发起方还是参与方?

根据当前的线程threadlocal 中获取事务分组id, 如果能够成功获取到则是为参与方,没有能够获取到就是为发起方。

参与方如何加入LCN全局协调者?

发起方会把事务id注册到协调者里面去,参与方根据请求头里面的事务分组id加入该事务。

发起方如何通知全局回滚还是提交?

发起方的方法执行完成之后,会修改事务状态,再根据全局协调者通知其他参与者事务执行完成。反之,如果发起方的方法执行方法异常,事务状态改为错误状态,再通过全局协调者发送给其他参与者,参与者再回滚事务即可。

A调用B,B调用C 到底会生产几次事务id?

每次原远程调用接口都会生成一个事务id,但是一条调用链上只有一个事务分组id(全局id)。只有A是发起方,B和C都是参与方。可以从请求头中获取到事务分组id就是参与方,表示加入到这个分组里面去的。

入口:@LcnTransaction,TransactionAspect 切面类。

feign 重写的拦截器,给请求头添加信息,事务分组id

到此这篇关于Java详细分析LCN框架分布式事务的文章就介绍到这了,更多相关Java LCN框架内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • mybatis执行错误但sql执行正常问题

    mybatis执行错误但sql执行正常问题

    这篇文章主要介绍了mybatis执行错误但sql执行正常问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Java日志框架之logback使用详解

    Java日志框架之logback使用详解

    这篇文章主要介绍了Java日志框架之logback使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • SkyWalking 自定义插件(Spring RabbitMQ)具体分析过程

    SkyWalking 自定义插件(Spring RabbitMQ)具体分析过程

    这篇文章主要介绍了SkyWalking 自定义插件(Spring RabbitMQ)具体分析过程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • mybatis注解之@Mapper和@MapperScan的使用

    mybatis注解之@Mapper和@MapperScan的使用

    这篇文章主要介绍了mybatis注解之@Mapper和@MapperScan的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 详解SpringMVC的拦截器链实现及拦截器链配置

    详解SpringMVC的拦截器链实现及拦截器链配置

    拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行。本文将详细讲讲SpringMVC中拦截器参数及拦截器链配置,感兴趣的可以尝试一下
    2022-08-08
  • Java获取环境变量(System.getenv)的方法

    Java获取环境变量(System.getenv)的方法

    本文主要介绍了Java获取环境变量(System.getenv)的方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • Java利用opencv实现用字符展示视频或图片的方法

    Java利用opencv实现用字符展示视频或图片的方法

    这篇文章主要介绍了Java利用opencv实现用字符展示视频或图片的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Maven中plugins与pluginManagement的区别说明

    Maven中plugins与pluginManagement的区别说明

    这篇文章主要介绍了Maven中plugins与pluginManagement的区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • java 动态生成bean的案例

    java 动态生成bean的案例

    这篇文章主要介绍了java 动态生成bean的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • JSP服务器端和前端出现乱码问题解决方案

    JSP服务器端和前端出现乱码问题解决方案

    这篇文章主要介绍了JSP服务器端和前端出现乱码问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02

最新评论