全局事务核心类:
一、通用逻辑:
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版本分析。