【源码分析】【seata】at 模式分布式事务 -server 端与客户端交互
写在前面
前段时间家里小狗生病,一直在忙着给他治病照顾她,最后还是没办法力挽狂澜,最后走了,作者情绪低落,所以停更了一段时间。上文介绍了 at 模式中 client 段是如何隐式传递分布式事务 id 的。而对于 server 端,我们还是充满了未知,不过我们知道的是,server 肯定会去处理之前源码分析说到的 rm,tm 发送给 coordinator 的各种请求,比如 tm 的开启分布式事务,rm 的注册分支事务,上报分支事务状态等等。本文就让我们以此做引来探究一下 server 端的逻辑。
版本约定
seata-server:1.1.0
名词约定
TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。实际功能是由 seata Server 承载的
TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。一般是注解 @GlobalTransactional 驱动的方法,作为当前分布式事务的 tm。
RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。分布式事务内的每个资源都是 rm,tm 通过 @GlobalTransactional 注解发起一下分布式事务,本身方法的业务逻辑也是一个 rm。
at 模式
通过每个 rm 自己去记录自身业务逻辑执行前后的数据库相关行记录快照,用于分布式事务集体回滚之后的数据恢复。
rpc
Remote Procedure Call 的简写。集群内,两台服务器由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。
带着疑问
本文开头也说了,我们目前对于 server 侧的逻辑判断,肯定是有和 client 端的 tm,rm 的交互的,毕竟需要处理 client 发出来的网络请求。我们也知道 server 端肯定还有一些协调的逻辑,那就让我们从交互的逻辑开始进入探究。
源码分析
先来看一下与 client 端的网络通信,我们这里可以从网络的入口开始,以此作为我们源码分析的入口。那么怎么找到网络通信的入口呢,我们知道很多开源的框架对于 nio 的实现都是使用 netty 的。而 netty 对于 io 消息的消费都是通过 io.netty.channel.ChannelInboundHandler#channelRead 来实现自己的逻辑的,seata 既然也是通过 netty 来做 nio 通信的,那我们就以此作为我们源码分析的入口。
我们从上图展示的 io.netty.channel.ChannelInboundHandler#channelRead 的实现类可以看到一共有四个地方使用到了。
第一个 AbstractHandler 是第二个,第三个的基类。从命名也可以看出第二个是客户端用的,第三个是服务端用的。至于第四个看下源码就可以发现,逻辑很简单,基本就是打印日志的逻辑。
这里简单带一下第二个哈,因为之前分析 client 端的逻辑也没有说到,作者也不打算再写这部分,因为看完本文,读者应该可以自己去分析客户端的逻辑了,因为客户端的逻辑,相比 server 的简单很多
那我们就以 io.seata.core.rpc.netty.AbstractRpcRemotingServer.ServerHandler 作为入口来进行源码分析。
ServerHandler 重写了基类的 channelRead 方法
那我就继续看一下其他消息的处理 io.seata.core.rpc.ServerMessageListener#onTrxMessage
下述源码其实是对于消息的基础类型进行了区分处理,核心逻辑都是 io.seata.core.rpc.TransactionMessageHandler#onRequest。有兴趣的同学可以跟一下源码,就会知道 seata 服务端使用的默认实现类是 DefaultCoordinator。
在 DefaultCoordinator 的实现中就可以看到对于不同请求类型的不同处理实现
下面作者举例几种请求类型
先说下分布式事务的开启。使用的是 GlobalBeginRequest(AbstractTransactionRequest 的子类实现)。真正创建分布式事务 id 的逻辑在 io.seata.server.coordinator.DefaultCore#begin
再说说分支事务的注册。核心逻辑在 io.seata.server.coordinator.AbstractCore#branchRegister
最后再说下全局事务的提交,这应该是最复杂的了。核心逻辑在 io.seata.server.coordinator.DefaultCore#commit
看完了与 client 的交互,最后我们再看看 server 端之前我们提到的门面类 DefaultCoordinator 的初始化做了啥
总结
本文解析了 seata 服务端与客户端的交互逻辑,和 server 自身的一些定时任务处理。到这里作者想跟大家分享的关于 seata 的部分就差不多结束了。如果读者还有什么觉得作者说的不够清晰,或者是还没有阐述到的部分内容,都可以私聊作者哈,作者很奔放的。后续作者想借着本文说的 netty 写一点分享,有什么好的方向推荐都可以跟作者说哈,感谢大家。也希望我的小狗家宝在那里一切都好,下辈子身体健康,幸福美满。最后放一张它的卡通照,想念。
评论