3

Seata 1.5.2 源码学习(Client端) - 废物大师兄

 1 year ago
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.
neoserver,ios ssh client

Seata 1.5.2 源码学习(Client端)

在上一篇中通过阅读Seata服务端的代码,我们了解到TC是如何处理来自客户端的请求的,今天这一篇一起来了解一下客户端是如何处理TC发过来的请求的。要想搞清楚这一点,还得从GlobalTransactionScanner说起。

874963-20221114161411189-1436441313.png

启动的时候,会调用GlobalTransactionScanner#initClient()方法,在initClient()中初始化TM和RM

TM初始化,主要是注册各种处理器,最终构造一个处理器映射表,不再多说

HashMap<Integer/*MessageType*/, Pair<RemotingProcessor, ExecutorService>> processorTable = new HashMap<>(32);
874963-20221114162328575-574305491.png
874963-20221118103500502-1784389000.png

重点关注RM初始化

874963-20221114163941746-911163803.png

RM初始化过程中,设置了 resourceManager 和 transactionMessageHandler,然后也是注册各种处理器,最终也是构造一个消息类型和对应的处理器的一个映射关系

874963-20221114164549014-180487892.png

可以看到,图中上半部分是RM特有的,下半部分与TM初始化注册处理器类似

然鹅,真正处理请求的还是靠调用各个处理器中的handler.onRequest()方法,于是问题的关键就很明显了,就在于handler

1.  ResourceManager

在了解ResourceManager之前,让我们首先了解一下ResourceManagerInbound和ResourceManagerOutbound

ResourceManagerInbound是处理接收到TC的请求的,是TC向RM发请求

874963-20221114170428067-1516323438.png

ResourceManagerOutbound是处理流出的消息的,是RM向TC发请求

874963-20221114170410475-525382875.png

ResourceManager继承了二者,所以既负责向TC发请求,又负责接收从TC来的请求。

还记得刚才在RMClient中是怎么获取ResourceManager的吗?是调用DefaultResourceManager.get()获取的

874963-20221114172305730-908186760.png
874963-20221114172349702-1014054827.png

874963-20221114172404285-172725049.png

DefaultResourceManager.get()得到的是一个单例DefaultResourceManager,创建DefaultResourceManager的时候会构建一个分支类型与ResourceManager的一个Map

874963-20221114173333446-454322071.png

2. TransactionMessageHandler

TransactionMessageHandler负责处理接收到的RPC消息

874963-20221114173849349-1049372952.png

前面在 RMClient 中通过 DefaultRMHandler.get() 获取 TransactionMessageHandler

874963-20221114174627435-2082058398.png
874963-20221114174701290-1698231375.png
874963-20221114174725293-239500198.png
874963-20221114180027321-561223327.png

3. 消息处理

874963-20221117162701035-584353571.png

RMClient#init()的时候new了一个RmNettyRemotingClient

874963-20221117164342940-435843444.png

这里要记住,rmNettyRemotingClient的两个成员变量此时已经被赋值了:

  • resourceManager是DefaultResourceManager,
  • transactionMessageHandler是DefaultRMHandler
874963-20221117181335164-1568891536.png

RmNettyRemotingClient构造方法中调用父类AbstractNettyRemotingClient的构造方法

874963-20221117181757924-1980265726.png
874963-20221117181804545-301471500.png
874963-20221117181814740-1058828647.png

可以看到,根据收到的RPC消息类型,从processorTable中获取对应的Processor,最后调用对应RemotingProcessor的process()方法进行处理消息

RemotingProcessor的实现类很多,挑其中一个RmBranchCommitProcessor看一下

874963-20221118114656780-2039011555.png
874963-20221118120033002-10593552.png
874963-20221118121049619-90495709.png

真相大白,最终还是调DefaultRMHandler#handle()

捋一下这个过程

874963-20221118121354974-422733695.png

最后,补充一个,this为什么是DefaultRMHandler

874963-20221118121506622-1274356285.png

补充二:AbstractTransactionRequestToRM

874963-20221118121631553-951700256.png

4. 分支事务提交(二阶段)

874963-20221118123159283-239781621.png
874963-20221118123211517-369950394.png
874963-20221118123233065-1540314544.png
874963-20221118123243240-1034894258.png
874963-20221118123249818-461390453.png

交给AsyncWorker去执行

874963-20221118172654867-735319873.png
874963-20221118170337218-1396135270.png

可以看到:

  1. 封装成一个Phase2Context对象,并将其放入队列中
  2. 如果放入成功,则立即返回提交成功,后续交由定时任务执行
  3. 如果放入失败,则主动触发定时任务先执行一次,以便腾出空间来,待执行完后,队列里面就有空间了,再将任务放入队列,等待下一次定时任务执行
  4. 定时任务1秒执行一次,执行的时候将队列中的任务取出,然后循环遍历分段执行
  5. 执行的过程就是删除对应事务的undo log
  6. 如果过程中抛异常,则将任务再放回队列中

所以,RM收到TC发的提交指令后,仅仅只是删除该事务的undo_log表记录

874963-20221118172916594-1541491108.png

5. 分支事务回滚(二阶段)

与提交类似

874963-20221118174936729-586736137.png
874963-20221118175001152-1937652130.png
874963-20221118175213523-13598267.png

所以,回滚就是根据事务的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发请求,回滚分支事务,还原数据

874963-20221118184025580-196798690.png
感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!
欢迎各位转载,但必须在文章页面中给出作者和原文链接!

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK