Seata 1.5.2 源码学习(Client端) - 废物大师兄
source link: https://www.cnblogs.com/cjsblog/p/16890035.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Seata 1.5.2 源码学习(Client端)
在上一篇中通过阅读Seata服务端的代码,我们了解到TC是如何处理来自客户端的请求的,今天这一篇一起来了解一下客户端是如何处理TC发过来的请求的。要想搞清楚这一点,还得从GlobalTransactionScanner说起。
启动的时候,会调用GlobalTransactionScanner#initClient()方法,在initClient()中初始化TM和RM
TM初始化,主要是注册各种处理器,最终构造一个处理器映射表,不再多说
HashMap<Integer/*MessageType*/, Pair<RemotingProcessor, ExecutorService>> processorTable = new HashMap<>(32);
重点关注RM初始化
RM初始化过程中,设置了 resourceManager 和 transactionMessageHandler,然后也是注册各种处理器,最终也是构造一个消息类型和对应的处理器的一个映射关系
可以看到,图中上半部分是RM特有的,下半部分与TM初始化注册处理器类似
然鹅,真正处理请求的还是靠调用各个处理器中的handler.onRequest()方法,于是问题的关键就很明显了,就在于handler
1. ResourceManager
在了解ResourceManager之前,让我们首先了解一下ResourceManagerInbound和ResourceManagerOutbound
ResourceManagerInbound是处理接收到TC的请求的,是TC向RM发请求
ResourceManagerOutbound是处理流出的消息的,是RM向TC发请求
ResourceManager继承了二者,所以既负责向TC发请求,又负责接收从TC来的请求。
还记得刚才在RMClient中是怎么获取ResourceManager的吗?是调用DefaultResourceManager.get()获取的
DefaultResourceManager.get()得到的是一个单例DefaultResourceManager,创建DefaultResourceManager的时候会构建一个分支类型与ResourceManager的一个Map
2. TransactionMessageHandler
TransactionMessageHandler负责处理接收到的RPC消息
前面在 RMClient 中通过 DefaultRMHandler.get() 获取 TransactionMessageHandler
3. 消息处理
RMClient#init()的时候new了一个RmNettyRemotingClient
这里要记住,rmNettyRemotingClient的两个成员变量此时已经被赋值了:
- resourceManager是DefaultResourceManager,
- transactionMessageHandler是DefaultRMHandler
RmNettyRemotingClient构造方法中调用父类AbstractNettyRemotingClient的构造方法
可以看到,根据收到的RPC消息类型,从processorTable中获取对应的Processor,最后调用对应RemotingProcessor的process()方法进行处理消息
RemotingProcessor的实现类很多,挑其中一个RmBranchCommitProcessor看一下
真相大白,最终还是调DefaultRMHandler#handle()
捋一下这个过程
最后,补充一个,this为什么是DefaultRMHandler
补充二:AbstractTransactionRequestToRM
4. 分支事务提交(二阶段)
交给AsyncWorker去执行
可以看到:
- 封装成一个Phase2Context对象,并将其放入队列中
- 如果放入成功,则立即返回提交成功,后续交由定时任务执行
- 如果放入失败,则主动触发定时任务先执行一次,以便腾出空间来,待执行完后,队列里面就有空间了,再将任务放入队列,等待下一次定时任务执行
- 定时任务1秒执行一次,执行的时候将队列中的任务取出,然后循环遍历分段执行
- 执行的过程就是删除对应事务的undo log
- 如果过程中抛异常,则将任务再放回队列中
所以,RM收到TC发的提交指令后,仅仅只是删除该事务的undo_log表记录
5. 分支事务回滚(二阶段)
与提交类似
所以,回滚就是根据事务的undo_log进行回滚
1、启动时,自动代理数据源,应用GlobalTransactionalInterceptor,初始化TM和RM
2、进入@GlobalTransactional业务方法时,TM向TC发请求申请开启全局事务,并获得全局事务ID
3、业务方法调用远程服务接口完成业务处理
4、RM执行本地逻辑,注册分支事务,获取全局锁,成功后提交本地事务并写入undo_log,本地事务提交成功后向TC报告分支事务
5、TM发起全局事务提交请求,TC向所有已注册的RM发请求,让RM进行分支提交,删除本地undo_log
6、若执行失败,TM发起全局事务回滚,TC向所有RM发请求,回滚分支事务,还原数据
欢迎各位转载,但必须在文章页面中给出作者和原文链接!
Recommend
-
4
Spring Security OAuth 笔记 1 单点登录 关于单点登录的原理,我觉得下面这位...
-
4
Redis 哈希Hash底层数据结构 1. Redis 底层数据结构
-
3
InnoDB 中不同SQL语句设置的锁 锁定读、UPDATE 或 DELE...
-
5
Java根据Freemarker模板生成Word文件 1. 准备模板...
-
4
Activiti 7 源码学习 1. 启动分析 源码版本是...
-
4
MySQL 窗口函数 1. 窗口函数概念和语法 窗口函...
-
4
Spring Retry 重试 重试的使用场景比较多,比如调用远...
-
1
Seata 1.5.2 源码学习 文章有点长,我决定用半个小时来...
-
4
Seata Server 1.5.2 源码学习 Seata 包括 Server端和Cl...
-
6
Spring Boot 多数据源配置 第一种方式: AbstractRouti...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK