在上一篇中通过阅读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去执行

可以看到:

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

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

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

与提交类似

所以,回滚就是根据事务的undo_log进行回滚

6. 总结

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发请求,回滚分支事务,还原数据

Seata 1.5.2 源码学习(Client端)的更多相关文章

  1. Seata 1.5.2 源码学习

    文章有点长,我决定用半个小时来给您分享~ 基于Seata 1.5.2,项目中用 seata-spring-boot-starter 1. SeataDataSourceAutoConfiguratio ...

  2. Netty 源码学习——服务端流程分析

    在上一篇我们已经介绍了客户端的流程分析,我们已经对启动已经大体上有了一定的认识,现在我们继续看对服务端的流程来看一看到底有什么区别. 服务端代码 public class NioServer { pr ...

  3. Seata Server 1.5.2 源码学习

    Seata 包括 Server端和Client端.Seata中有三种角色:TC.TM.RM,其中,Server端就是TC,TM和RM属Client端.Client端的源码学习上一篇已讲过,详见 < ...

  4. Dubbo源码学习--注册中心分析

    相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 注册中心 关于注册中心,Dubbo提供了多个实现方式,有比较成熟的使用zookeeper 和 redis 的 ...

  5. 【Spark2.0源码学习】-1.概述

          Spark作为当前主流的分布式计算框架,其高效性.通用性.易用性使其得到广泛的关注,本系列博客不会介绍其原理.安装与使用相关知识,将会从源码角度进行深度分析,理解其背后的设计精髓,以便后续 ...

  6. Redis源码学习:字符串

    Redis源码学习:字符串 1.初识SDS 1.1 SDS定义 Redis定义了一个叫做sdshdr(SDS or simple dynamic string)的数据结构.SDS不仅用于 保存字符串, ...

  7. 【Netty源码学习】ChannelPipeline(一)

    ChannelPipeline类似于一个管道,管道中存放的是一系列对读取数据进行业务操作的ChannelHandler. 1.ChannelPipeline的结构图: 在之前的博客[Netty源码学习 ...

  8. spark2.0源码学习

    [Spark2.0源码学习]-1.概述 [Spark2.0源码学习]-2.一切从脚本说起 [Spark2.0源码学习]-3.Endpoint模型介绍 [Spark2.0源码学习]-4.Master启动 ...

  9. Hadoop源码学习笔记(6)——从ls命令一路解剖

    Hadoop源码学习笔记(6) ——从ls命令一路解剖 Hadoop几个模块的程序我们大致有了点了解,现在我们得细看一下这个程序是如何处理命令的. 我们就从原头开始,然后一步步追查. 我们先选中ls命 ...

  10. Hadoop源码学习笔记(4) ——Socket到RPC调用

    Hadoop源码学习笔记(4) ——Socket到RPC调用 Hadoop是一个分布式程序,分布在多台机器上运行,事必会涉及到网络编程.那这里如何让网络编程变得简单.透明的呢? 网络编程中,首先我们要 ...

随机推荐

  1. Linux 配置ODBC连接Oracle

    在使用kdb_database_link 扩展插件连接Oracle数据库时,必须先配置ODBC,确保通过ODBC能连接Oracle数据库.以下是配置ODBC的过程. 一.安装ODBC 1.安装 [ro ...

  2. 微软出品自动化神器Playwright,不用写一行代码(Playwright+Java)系列(一) 之 环境搭建及脚本录制

    一.前言 半年前,偶然在视频号刷到某机构正在直播讲解Playwright框架的使用,就看了一会,感觉还不错,便被种草,就想着自己有时间也可以自己学一下,这一想着就半年多过去了. 读到这,你可能就去百度 ...

  3. Windows编程之线程同步

    本笔记整理自:<Windows核心编程(第五版)> 目录 什么是线程同步 用户方式中的线程同步 原子访问:Interlocked系列函数 CRITICAL_SECTION:关键段 内核对象 ...

  4. 进阶:spring-bean生命周期流程

    Bean的生成过程 主要流程图 1. 生成BeanDefinition Spring启动的时候会进行扫描,会先调用org.springframework.context.annotation.Clas ...

  5. stm32fxx_hal_i2c.c解读之HAL_I2C_Mem_Write

    HAL_I2C_Mem_Write()函数位于stm32fxx_hal_i2c.c文件的2432行,源代码对该函数的解释如下图 HAL_StatusTypeDef HAL_I2C_Mem_Write( ...

  6. 2022 CLion 中的Cygwin 配置(最全,最良心版)

    目录 前景提要 一.windows 10 安装Cygwin 1.找到官网,进入官网,百度搜索或者点击下边链接. 2.找到如图位置,双击下载 3.下载完成后,找到下载的位置,双击exe文件. 4.进入欢 ...

  7. day01-项目开发流程

    多用户即时通讯系统01 1.项目开发流程 2.需求分析 用户登录 拉取在线用户列表 无异常退出(包括客户端和服务端) 私聊 群聊 发文件 服务器推送新闻/广播 3.设计阶段 3.1界面设计 用户登录: ...

  8. 基于electron+vue+element构建项目模板之【创建项目篇】

    1.概述 electron:使用javascript.css.html构建跨平台的桌面应用程序 vue:数据驱动视图中的一款渐进式的javascript框架 element:基于vue的桌面端UI组件 ...

  9. 使用Gitlab CI/CD功能在本地部署 Spring Boot 项目

    前提条件: 1.Docker安装Gitlab,地址:https://www.cnblogs.com/sanduzxcvbnm/p/13814730.html 2.Docker安装Gitlab-runn ...

  10. 使用 Elastic 技术栈构建 K8S 全栈监控 -1:搭建 ElasticSearch 集群环境

    文章转载自:https://www.qikqiak.com/post/k8s-monitor-use-elastic-stack-1/ 操作步骤 kubectl create ns elastic k ...