文章目录
一、首先介绍3.0与4.0之前的差异
1、地址:
2、4.0添加升级如下功能:
(1)3.0虽然有事务补偿机制,但4.0在此基础上不仅添加事务补偿机制的策性,还添加了管理的后台可以看到补偿的数据;同时也添加了一个回调地址,可以在补偿之前可以最先知道这次补偿的数据,也可以为我们的框架使用者提供一个决策权。
(2)同4.0时添加的插件扩展机制,也就是说他更加开放了,他可以可以容纳更多的rpc框架,也可以更多的支持db框架,比如mongodb、redis,还有将来一些框架,如ES等等。
二、LCN4.0原理
1、架构介绍
有图可得,lcn是通过nginx作为负载均衡的转发,也就是作为Txmanager的负载均衡的一个转发服务器;然后再是我们的TxManager,也就是事务管理器,然后事务管理器依赖两个服务,一个是redis服务,一个是Eureka服务集群;Eureka集群是用于我们TxManager之间的相互服务发现。redis是用于存放我们事务组的信息以及补偿的信息。然后模块A与模块B他们都需要去配置上我们TxClient的包架构(代码的包架构);来支持我们的LCN框架,以及他们的数据库。
2、核心步骤(LCN核心的三步骤)
首先讲解下什么是事务组:事务组是指的我们在整个事务过程中把各个节点(微服务)单元的事务信息存储在一个固定单元里。但这个信息并不是代表是事务信息,而是只是作为一个模块的标示信息。
其次介绍事务发起者与参与者
如图,在一次事务中发起的就叫做启动者或者是发起方。然后其他的微服务框架都叫做事务的参与者。
1.创建事务组
是指在事务发起方代码开始执行业务之前先调用TxManager创建事务组对象,然后拿到事务标示GroupId的过程。(这里的groupId表示的是一次事务的唯一标示,就是指我们一次事务中,会有一个groupId存在。其次这里讲述在开始执行业务之前,是因为框架是基于切面的思想,那么切面就切面到了这个方法的业务执行过程中,然后又一个around切面。再然后在开始之前,在业务没有调用业务之前会先调用TxManager去创建事务组,然后创建完事务组以后Txmanager会返回事务组信息,事务组信息中就包含GroupId这个参数,这也就是作为的创建事务组。创建完事务组之后就相当于已经产生一个事务组标示。作为一个串联过程,识别为同一次事务的一个过程)
2.添加事务组
添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息添加通知给TxManager的操作。
3.关闭事务组
是指在发起方执行完业务代码以后(执行到这个地方就表明没有错误和异常,也就是执行结束了,否则并不会执行到这个地方),将发起方执行结果状态通知给TxManager的动作。当执行完关闭事务组的方法以后,TxManager将根据事务组信息来通知相应的参与模块提交或回滚事务。
3、事务协调机制
如图:假设服务已经执行到关闭事务组的过程,那么接下来作为一个模块执行通知给TxManager,然后告诉他本次事务已经完成。那么如图中Txmanager下一个动作就是通过事务组的id,然后获取到本次事务组的事务信息;然后查看一下对应有那几个模块参与,然后如果是有A/B/C三个模块;那么对应的对三个模块做通知、提交、回滚。
那么提交的时候是提交给谁呢?
是提交给了我们的TxClient模块。然后TxCliient模块下有一个连接池,就是框架自定义的一个连接池(如图DB连接池);这个连接池其实就是在没有通知事务之前一直占有着这次事务的连接资源,就是没有释放。但是他在切面里面执行了close方法。在执行close的时候。如果需要(TxManager)分布式事务框架的连接。他被叫做“假关闭”,也就是没有关闭,只是在执行了一次关闭方法。实际的资源是没有释放的。这个资源是掌握在LCN的连接池里的。
然后当TxManager通知提交或事务回滚的时候呢?
TxManager会通知我们的TxClient端。然后TxClient会去执行相应的提交或回滚。提交或回滚之后再去关闭连接,然后在返回给DB连接池。这就只事务的协调机制。说白了就是代理DataSource的机制;相当于是拦截了一下连接池,控制了连接池的事务提交。
该部分源码可看:https://github.com/syzpig/tx-lcn
LCN事务控制原理是由事务模块TxClient下的代理连接池与TxManager的协调配合完成的事务协调控制。
TxClient的代理连接池实现了javax.sql.DataSource接口,并重写了close方法,事务模块在提交关闭以后TxClient连接池将执行"假关闭"操作,等待TxManager协调完成事务以后在关闭连接。
对于代理连接池的优化
1.自动超时机制
任何通讯都有最大超时限制,参与模块在等待通知的状态下也有最大超时限制,当超过时间限制以后事务模块将先确认事务状态,然后再决定执行提交或者回滚操作,主要为了给最大资源占用时间加上限制。
2.智能识别创建不同的连接 对于只读操作、非事务操作LCN将不开启代理功能,返回本地连接对象,对于补偿事务的启动方将开启回滚连接对象,执行完业务以后马上回滚事务。
3.LCN连接重用机制 当模块在同一次事务下被重复执行时,连接资源会被重用,提高连接的使用率。
4、补偿机制
为什么需要事务补偿?
事务补偿是指在执行某个业务方法时,本应该执行成功的操作却因为服务器挂机或者网络抖动等问题导致事务没有正常提交,此种场景就需要通过补偿来完成事务,从而达到事务的一致性。
补偿机制的触发条件?
当执行关闭事务组步骤时,若发起方接受到失败的状态后将会把该次事务识别为待补偿事务,然后发起方将该次事务数据异步通知给TxManager。TxManager接受到补偿事务以后先通知补偿回调地址,然后再根据是否开启自动补偿事务状态来补偿或保存该次切面事务数据。
补偿事务机制?
LCN的补偿事务原理是模拟上次失败事务的请求,然后传递给TxClient模块然后再次执行该次请求事务。
简单的说:lcn事务补偿是在在服务挂机和网络抖动情况下;服务挂机是指在完成三个核心步骤的时候
尤其也只有最后一步关闭事务组时,让我去执行关闭事务组的时候,比如本次事务是要提交的。txManager接收到提交的请求再去通知的时候发现通知不到了。
(通知不到也就两种原因服务挂了和网络出问题)在这种情况下TxManager会做一个标示;然后返回给发起方。告诉他本次事务有存在没有通知到的情况。
那么如果是接收到这个信息之后呢,发起方就会做一个标示,标示本次事务是需要补偿事务的。这就是事务补偿机制。
LCN是怎么去实现事务补偿呢?
首先他或根据发起方拿到的TxManager的标示之后,判断是否需要做事务补偿,不过需要,他会首先在本地去记录一下日志 ,然后再把本次切面的信息,也就是发起方本次事务切面的信息
以及事务组的id信息提交给TxManager;然后TxManager接收到这次数据之后,他会查询到本次事务组的整个信息,获取到本次事务组信息之后呢,他会把这些信息一块保存到redis下,也就是做为补偿数据一块存下来。
在存下来的时候,他会先执行一次叫做回调接口的请求;这个回调接口其实是指的是回调给第三方服务的一个地址,也就是我们自己的服务地址。这里是作为一次通知用的,我们来看下4.0的界面
当补偿发生之后,TxManager记录完数据以后会通知这个回调接口地址如图:
告诉你有补偿信息存在。这个地方我们就可以做一些通知,例如邮件、短信提醒功能,通知给相应的人员。让他们知道现在我们的服务里存在了补偿,要及时处理。
当然你也可以开启自动补偿功能(如上图),当开启自动补偿之后的话,当补偿上传上来他也会通知的上面补偿回调接口,通知完之后,他会把本次事务去补偿一下。他是如何执行的呢?上面说到的他会把切面的信息上传上来,他会把切面的信息
上传给发起方,传递给发起方以后让发起方重复执行本次事务。但是有一个差异性的地方是在于,他在去做模块提交的时候呢,会根据历史的提交数据(补偿数据)做一个逆向的操作,也就是说,必须如下图来说:
比如我们这三个模块demo1、demo2、demo3.那么现在如果通知demo2通知成功,是在指没有补偿之前(也就是正常执行的事务状态下)。在通知demo3失败了。然后这一次作为补偿通知给了发起方demo1,发起方调用TxManager,告诉他这一次需要补偿
那么TxManager下发信息给demo1,demo1执行补偿的时候呢,首先启动方事务是要回滚的(异常的状态下不会执行补偿);那么demo2、demo3是否回滚取决于上次的事务请求。上面说demo2提交成功了,也就是说他要回滚,demo3失败,他是要补偿的,是要提交的。那么怎
么去实现这一点呢?还是跟以前一样,就是说其实这次是与之前的执行事务流程是相同的;唯一不同的是在于执行关闭,就是在这次补偿的事务过程中的关闭事务的时候。
TxManager会判断历史数据,然后在下发数据的时候,会根据历史数据(补偿数据)做差异性的通知,是判断谁要需要提交,谁需要回滚。这就是补偿机制的原理。然后早demo1发起方调用本次补偿的时候(也就是重新发起这次调用的话)肯定是基于反向代理的方式实现的。
5、插件机制
如图:
想要接入其他rpc和数据库框架可以参考如图中模块,如果项目lcn事务想引入redis数据库,直接引入上面tx-plugins-redis插件代码即可或者仿照其他插件。
代码地址:https://github.com/codingapi/tx-lcn
拟场景演示模
若存在事务发起方、参与方A、参与方B。调用关系图如下
那么他们正常执行业务的时序图为:
若参与方B出现异常,那么他们的业务时序图为:
若他们的调用关系是这样的情况
此时发生参与方B出现异常时他们的时序图为: