seata分布式事务源码解读

全局事务核心类:

一、通用逻辑:

0、io.seata.spring.annotation.GlobalTransactionScanner 全局事务扫描类,初始化Bean时调用io.seata.spring.annotation.GlobalTransactionScanner#wrapIfNecessary方法创建全局事务拦截器,

TCC模式(Bean方法有@TwoPhaseBusinessAction注解)创建TccActionInterceptor放入Bean的拦截器链中,其他模式(Bean方法有@GlobalTransactional注解 )创建GlobalTransactionalInterceptor放入Bean的拦截器链中。

0.1 业务类在执行被@GlobalTransactional注解的方法时,会先执行io.seata.spring.annotation.GlobalTransactionalInterceptor#invoke,触发全局事务执行逻辑。

io.seata.spring.annotation.GlobalTransactionalInterceptor#invoke ->

io.seata.spring.annotation.GlobalTransactionalInterceptor#handleGlobalTransaction ->

io.seata.tm.api.TransactionalTemplate#execute

1、io.seata.tm.api.TransactionalTemplate#execute 模板类,定义了全局事务执行的核心流程,TM发起一个全局事务最终会调用到该方法:

1.1、解析 @GlobalTransactional(timeoutMills = 13000000, name = “dubbo-demo-tx2”) 获取全局事务配置

TransactionInfo txInfo = business.getTransactionInfo(); //52

1.2、根据propagation属性处理全局事务的传播特性: //63

NOT_SUPPORTED:不需要全局事务,将全局事务xid在当前Thread Local中解绑后直接执行业务方法。

REQUIRES_NEW:在新的全局事务中运行,暂停原来的全局事务。(在当前Thread Local中解绑旧的xid,创建一个新的xid并绑定)

SUPPORTS:支持原来的全局事务,原来存在则继续执行,不存在则不做后续处理直接执行业务方法。

REQUIRED:必须开启全局事务,原来存在则在原来事务中执行,原来不存在则创建新的xid。

NEVER:不允许在全局事务中运行,存在则抛出异常,不存在则不做后续处理直接执行业务方法。

MANDATORY:必须在全局事务下运行,不存在则抛出异常,存在则继续执行后续逻辑。

default:抛出异常。

1.3、开启全局事务,向TC注册

beginTransaction(txInfo, tx); //122

客户端执行路径:

io.seata.tm.api.TransactionalTemplate#beginTransaction ->

io.seata.tm.api.DefaultGlobalTransaction#begin(int, java.lang.String) ->

io.seata.tm.DefaultTransactionManager#begin ->

io.seata.tm.DefaultTransactionManager#syncCall ->

io.seata.core.rpc.netty.AbstractNettyRemotingClient#sendSyncRequest(java.lang.Object)

最终会同步调用TC服务的注册接口,并标记全局事务的状态。

TC服务端接收处理:

io.seata.core.rpc.netty.AbstractNettyRemoting#processMessage ->

this.processorTable.get((int) messageTypeAware.getTypeCode()) 从注册的处理器中取出对应的处理器进行处理,处理器注册io.seata.core.rpc.netty.NettyRemotingServer#registerProcessor

#MessageType.TYPE_GLOBAL_BEGIN 对应的处理器是 io.seata.core.rpc.processor.server.ServerOnRequestProcessor

io.seata.core.rpc.processor.server.ServerOnRequestProcessor#process ->

io.seata.server.coordinator.DefaultCoordinator#onRequest ->

io.seata.core.protocol.transaction.GlobalBeginRequest#handle ->

io.seata.server.AbstractTCInboundHandler#handle(io.seata.core.protocol.transaction.GlobalBeginRequest, io.seata.core.rpc.RpcContext) ->

io.seata.server.coordinator.DefaultCoordinator#doGlobalBegin ->

io.seata.server.coordinator.DefaultCore#begin ->

io.seata.server.session.GlobalSession#begin ->

io.seata.server.storage.db.session.DataBaseSessionManager#addGlobalSession ->

最终把全局session信息(GlobalTransactionDO)保存到数据库表(global_table)/redis/文件…

1.4、处理业务逻辑

rs = business.execute(); //127

执行被@GlobalTransactional注解的业务方法

业务方法内部可以是本地事务提交或者RPC调用,本地事务提交会被io.seata.rm.datasource.ConnectionProxy代理(AT模式流程2)

或者分布式事务分支方法执行会被io.seata.spring.tcc.TccActionInterceptor#invoke处理(TCC模式流程3),

或本地事务提交会被io.seata.rm.datasource.xa.DataSourceProxyXA代理(XA模式流程6)

RPC调用会把xid传递给被调用方(流程1.5),被调用方提交事务也会被io.seata.rm.datasource.ConnectionProxy代理(AT模式流程2)

或者分布式事务分支方法执行会被io.seata.spring.tcc.TccActionInterceptor#invoke处理(TCC模式流程3),

或本地事务提交会被io.seata.rm.datasource.xa.DataSourceProxyXA代理(XA模式流程6)。

1.5、RPC调用传递xid

io.seata.integration.dubbo.ApacheDubboTransactionPropagationFilter#invoke

RpcContext.getContext().setAttachment(RootContext.KEY_XID, xid);

1.6、全局事务提交 io.seata.tm.api.TransactionalTemplate#commitTransaction //135

io.seata.tm.api.TransactionalTemplate#commitTransaction ->

io.seata.tm.api.DefaultGlobalTransaction#commit -> #只有事务发起方(TM)才可以提交全局事务 role == GlobalTransactionRole.Launcher

io.seata.tm.DefaultTransactionManager#commit ->

io.seata.tm.DefaultTransactionManager#syncCall ->

最后通过调用TC服务接口提交全局事务。

1.7、恢复挂起的事务。(结合1.2)

tx.resume(suspendedResourcesHolder); //147

二、AT模式:需要注入io.seata.rm.datasource.SeataDataSourceProxy代理类

2、io.seata.rm.datasource.ConnectionProxy是本地数据库连接java.sql.Connection的代理实现类,代理实现本地事务的提交回滚,加入全局事务的控制逻辑,实现AT模式分布式事务的提交回滚等操作。

io.seata.rm.datasource.DataSourceProxy是io.seata.rm.datasource.SeataDataSourceProxy的实现类,主要作为AT\TCC\SAGA模式的数据源代理实现类,

io.seata.rm.datasource.xa.DataSourceProxyXA也是io.seata.rm.datasource.SeataDataSourceProxy的实现类,主要作为XA模式的数据源代理实现类。

ConnectionProxy#commit()流程:

io.seata.rm.datasource.ConnectionProxy#commit ->

io.seata.rm.datasource.ConnectionProxy#doCommit ->

2.1、如果在全局事务范围内则执行 io.seata.rm.datasource.ConnectionProxy#processGlobalTransactionCommit //230

首先注册分支事务:io.seata.rm.datasource.ConnectionProxy#register -> io.seata.rm.AbstractResourceManager#branchRegister

然后生成undolog,将保存undolog事务加入本地事务:UndoLogManagerFactory.getUndoLogManager(this.getDbType()).flushUndoLogs(this);

最后保存本地事务:targetConnection.commit();

2.2、如果需要申请全局锁(@GlobalLock标记的方法)则执行io.seata.rm.datasource.ConnectionProxy#processLocalCommitWithGlobalLocks //232

检查是否存在全局锁:io.seata.rm.datasource.ConnectionProxy#checkLock

存在则抛出异常:throw new LockConflictException();

不存在则提交事务:targetConnection.commit();

2.3、否则直接执行本地事务提交:targetConnection.commit() //234

三、TCC模式:不需要数据库代理,需要提供分支事务提交回滚方法(使用@TwoPhaseBusinessAction修饰)

3、io.seata.spring.tcc.TccActionInterceptor拦截处理@TwoPhaseBusinessAction注解的方法调用,解析全局事务参数,加入全局事务的控制逻辑,实现TCC模式分布式事务的提交回滚等操作。

io.seata.spring.tcc.TccActionInterceptor#invoke ->

io.seata.rm.tcc.interceptor.ActionInterceptorHandler#proceed ->

io.seata.rm.tcc.interceptor.ActionInterceptorHandler#doTccActionLogStore ->

io.seata.rm.AbstractResourceManager#branchRegister ->

注册分支事务后执行业务逻辑:targetCallback.execute()

四、SAGA模式:

4

五、XA模式

5

六、TC端处理逻辑

6、seata-server通过io.seata.server.Server#start会初始化一系列组件:io.seata.core.rpc.netty.NettyRemotingServer、io.seata.server.session.SessionHolder、io.seata.server.lock.LockerManagerFactory、io.seata.server.coordinator.DefaultCoordinator… 这些组件启动后就可以处理客户端发起的分布式事务注册、提交、回滚等操作。

io.seata.server.Server#start

6.1、NettyRemotingServer nettyRemotingServer = new NettyRemotingServer(workingThreads); //74

首先创建NettyRemotingServer组件,该组件会构建Netty服务,绑定端口监听连接,注册一系列处理器处理客户端请求。

6.2、SessionHolder.init(); //78 初始化session组件

sessionMode = StoreConfig.getSessionMode(); //100

if (SessionMode.DB.equals(sessionMode)) { //102

ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, SessionMode.DB.getName());

DISTRIBUTED_LOCKER = DistributedLockerFactory.getDistributedLocker(SessionMode.DB.getName());

}

根据配置初始化对应的SessionManager、DistributedLocker,SessionManager管理(crud)分布式事务中的Session信息, DistributedLocker管理(锁申请和释放)分布式锁信息。

DataBaseSessionManager、FileSessionManager、RedisSessionManager分别将session保存到数据库(global_table表)、本地文件、redis中。

DataBaseDistributedLocker、RedisDistributedLocker、DefaultDistributedLocker分别通过数据库(distributed_lock表)、redis、默认实现分布式锁。

6.3、LockerManagerFactory.init(); //79 初始化记录锁管理组件

io.seata.server.lock.LockerManagerFactory#init(io.seata.server.store.StoreConfig.LockMode)

LOCK_MANAGER = EnhancedServiceLoader.load(LockManager.class, lockMode.getName()); //63

根据配置加载对应的LockManager,LockManager管理分布式事务中记录锁的管理(@GlobalLock+forupdate实现读提交。

DataBaseLockManager、RedisLockManager、FileLockManager分别通过数据库(lock_table表)、redis、本地文件的方式实现记录锁。

6.4、DefaultCoordinator coordinator = DefaultCoordinator.getInstance(nettyRemotingServer); //80 加载分布式事务协调器组件

io.seata.server.coordinator.DefaultCoordinator#getInstance(io.seata.core.rpc.RemotingServer) ->

io.seata.server.coordinator.DefaultCoordinator#DefaultCoordinator ->

io.seata.server.coordinator.DefaultCore#DefaultCore ->

List allCore = EnhancedServiceLoader.loadAll(AbstractCore.class, new Class[] {RemotingServer.class}, new Object[] {remotingServer});

这里会加载不同模式的协调器,协调器组件主要功能包括事务注册、事务上报、事务提交、事务回滚、锁申请、所释放等功能。DefaultCoordinator对外提供分布式事务的一系列接口,底层则根据配置调用不同的实现,对外隐藏实现细节。

协调器实现包括:

io.seata.server.transaction.at.ATCore

io.seata.server.transaction.tcc.TccCore

io.seata.server.transaction.saga.SagaCore

io.seata.server.transaction.xa.XACore

不同协调器实现继承模板类AbstractCore,该类实现分支事务注册、分支事务提交、分支事务上报等通用方法,全局事务由DefaultCoordinator控制。

例如事务的开启:io.seata.server.coordinator.DefaultCore#begin

GlobalSession session = GlobalSession.createGlobalSession(applicationId, transactionServiceGroup, name, timeout); //132 创建session对象

session.begin(); ->io.seata.server.session.GlobalSession#begin->io.seata.server.session.AbstractSessionManager#writeSession

最终会调用对应的SessionManager保存session信息,返回对应的全局事务xid。

6.5、coordinator.init(); //81 初始化协调器组件

io.seata.server.coordinator.DefaultCoordinator#init

主要是初始化5个定时任务(默认1秒钟执行一次),定时任务采用不同的线程池执行实现资源隔离,防止任务之间互相干扰:

io.seata.server.coordinator.DefaultCoordinator#handleRetryRollbacking:

回滚重试定时任务,查询状态为io.seata.server.coordinator.DefaultCoordinator#rollbackingStatuses的全局事务,调用io.seata.server.coordinator.DefaultCore#doGlobalRollback进行事务回滚。

io.seata.server.coordinator.DefaultCoordinator#handleRetryCommitting:

提交重试定时任务,查询状态为io.seata.server.coordinator.DefaultCoordinator#retryCommittingStatuses的全局事务,调用io.seata.server.coordinator.DefaultCore#doGlobalCommit进行事务提交。

io.seata.server.coordinator.DefaultCoordinator#handleAsyncCommitting:

异步提交定时任务,查询状态为io.seata.core.model.GlobalStatus#AsyncCommitting的全局事务,调用io.seata.server.coordinator.DefaultCore#doGlobalCommit进行事务提交。

io.seata.server.coordinator.DefaultCoordinator#timeoutCheck:超时事务处理定时任务,查询状态为io.seata.core.model.GlobalStatus#Begin的全局事务,调用io.seata.server.session.GlobalSession#close、io.seata.server.session.GlobalSession#changeGlobalStatus更新全局事务状态为GlobalStatus.TimeoutRollbacking。

io.seata.server.coordinator.DefaultCoordinator#undoLogDelete:

删除undolog定时任务,获取注册到该tc服务的客户端(ChannelManager.getRmChannels()),异步请求删除日志(UndoLogDeleteRequest)rpc接口(默认删除7天以前的undo_log表记录)。

6.6、nettyRemotingServer.init();//87 初始化nettyServer并启动

io.seata.core.rpc.netty.NettyRemotingServer#init ->

io.seata.core.rpc.netty.NettyRemotingServer#registerProcessor -> 注册消息处理器,对io.seata.core.protocol.MessageType进行分类,

不同类型的处理器有ServerOnRequestProcessor:处理请求类消息,ServerOnResponseProcessor:处理相应类消息,RegRmProcessor:处理rm注册消息,RegTmProcessor:处理tm注册消息,ServerHeartbeatProcessor:处理心跳消息。

io.seata.core.rpc.netty.AbstractNettyRemotingServer#init ->

serverBootstrap.start();

最后绑定监听端口启动nettyServer。至此tc端就可以接收客户端的分布式事务请求了。

seata客户端-服务端连接校验逻辑

seata client启动时通过注册中心查找要注册的集群实例列表,启动定时任务去连接tc服务端列表,在内存保持客户端和服务端正常连接的channel。

代码路径:

通过BeanFactory创建GlobalTransactionScanner,代码路径:

io.seata.spring.annotation.GlobalTransactionScanner#GlobalTransactionScanner(java.lang.String, java.lang.String)->

io.seata.spring.annotation.GlobalTransactionScanner#GlobalTransactionScanner(java.lang.String, java.lang.String, int)->

io.seata.spring.annotation.GlobalTransactionScanner#GlobalTransactionScanner(java.lang.String, java.lang.String, int, io.seata.tm.api.FailureHandler)->

GlobalTransactionScanner类有两个属性:accessKey、secretKey,在连接tc时传递给tc做校验用的,但是构造方法并没有提供参数初始化。在afterPropertiesSet()方法中也没有设置该值的地方。

new完后由Beanfactory调用 io.seata.spring.annotation.GlobalTransactionScanner#afterPropertiesSet方法:

io.seata.spring.annotation.GlobalTransactionScanner#afterPropertiesSet->

io.seata.spring.annotation.GlobalTransactionScanner#initClient ->

io.seata.tm.TMClient#init(java.lang.String, java.lang.String, java.lang.String, java.lang.String)->

io.seata.core.rpc.netty.TmNettyRemotingClient#getInstance(java.lang.String, java.lang.String, java.lang.String, java.lang.String)-> 这里会把accessKey、secretKey赋值给该对象。

io.seata.core.rpc.netty.TmNettyRemotingClient#getInstance()->

io.seata.core.rpc.netty.TmNettyRemotingClient#TmNettyRemotingClient ->

io.seata.core.rpc.netty.AbstractNettyRemotingClient#AbstractNettyRemotingClient->

io.seata.core.rpc.netty.NettyClientChannelManager#NettyClientChannelManager

NettyClientChannelManager构造方法中第二个参数 getPoolKeyFunction()最终调的是:

io.seata.core.rpc.netty.TmNettyRemotingClient#getPoolKeyFunction

或者io.seata.core.rpc.netty.RmNettyRemotingClient#getPoolKeyFunction

getPoolKeyFunction会通过方法 io.seata.core.rpc.netty.TmNettyRemotingClient#getExtraData 构造请求对象,包括accessKey、secretKey

初始化TmNettyRemotingClient后继续调用 init方法,这里会通过定时任务去连接tc:

io.seata.core.rpc.netty.TmNettyRemotingClient#init->

io.seata.core.rpc.netty.AbstractNettyRemotingClient#getClientChannelManager->

io.seata.core.rpc.netty.NettyClientChannelManager#reconnect->

io.seata.core.rpc.netty.NettyClientChannelManager#doConnect->

io.seata.core.rpc.netty.NettyPoolableFactory#makeObject->

io.seata.core.rpc.netty.AbstractNettyRemotingClient#sendSyncRequest(io.netty.channel.Channel, java.lang.Object)->

到这里会调用tc的注册接口进行注册。

tc端的处理逻辑:

io.seata.core.rpc.processor.server.RegTmProcessor#onRegTmMessage ->

io.seata.core.rpc.RegisterCheckAuthHandler#regTransactionManagerCheckAuth

RegisterCheckAuthHandler是需要我们实现的校验接口

系统默认提供的实现是io.seata.server.auth.DefaultCheckAuthHandler,默认返回true。

所以我们可以自己实现该接口后,修改src/main/resources/META-INF/services/io.seata.core.rpc.RegisterCheckAuthHandler内容为自定义类,

或者直接修改默认的实现。

accesskey和secretkey的签名参考 io.seata.core.rpc.netty.TmNettyRemotingClient#getExtraData

基于seata-all-1.4.2、seata-2.x版本分析。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值