Seata AT 模式理论学习及部分源码解析 | Spring Cloud 52

news2024/9/21 3:36:15

理论部分来自Seata官网:http://seata.io/zh-cn/docs/dev/mode/at-mode.html

一、前提

  • 基于支持本地 ACID 事务的关系型数据库。
  • Java 应用,通过 JDBC 访问数据库。

二、整体机制

两阶段提交协议的演变:

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。

  • 二阶段:

    • 提交异步化,非常快速地完成。
    • 回滚通过一阶段的回滚日志进行反向补偿。

三、写隔离

  • 一阶段本地事务提交前,需要确保先拿到 全局锁
  • 拿不到 全局锁 ,不能提交本地事务。
  • 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。
    以一个示例来说明:

两个全局事务 tx1tx2,分别对 a 表的 m 字段进行更新操作,m 的初始值 1000

  1. tx1 先开始,开启本地事务,拿到本地锁,更新操作 m = 1000 - 100 = 900

  2. 本地事务提交前,先拿到该记录的 全局锁 ,本地提交释放本地锁。

  3. tx2 后开始,开启本地事务,拿到本地锁,更新操作 m = 900 - 100 = 800

  4. 本地事务提交前,尝试拿该记录的 全局锁tx1 全局提交前,该记录的全局锁被 tx1 持有,tx2 需要重试等待 全局锁

在这里插入图片描述
tx1 二阶段全局提交,释放 全局锁 。tx2 拿到 全局锁 提交本地事务。

在这里插入图片描述
如果 tx1 的二阶段全局回滚,则 tx1 需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。

此时,如果 tx2 仍在等待该数据的 全局锁,同时持有本地锁,则 tx1 的分支回滚会失败。分支的回滚会一直重试,直到 tx2全局锁 等锁超时,放弃 全局锁 并回滚本地事务释放本地锁,tx1 的分支回滚最终成功。

因为整个过程 全局锁tx1 结束前一直是被 tx1 持有的,所以不会发生 脏写 的问题。

结论:
写隔离:如果业务表的更新操存在于分布式事务中和本地事务方法中,建议在本地事务方法上使用@GlobalTransaction@GlobalLock注解防止出现数据脏写,其中:

  • 属性值lockRetryInterval覆盖全局配置client.rm.lock.retryInterval校验或占用全局锁重试间隔
  • 属性值lockRetryTimes覆盖全局配置client.rm.lock.retryTimes校验或占用全局锁重试次数

四、读隔离

目前数据库事务的隔离级别一共有 4 种,由低到高分别为:

  • Read uncommitted:读未提交
  • Read committed:读已提交
  • Repeatable read:可重复读
  • Serializable:序列化

在数据库本地事务隔离级别 读已提交Read Committed) 或以上的基础上,SeataAT 模式)的默认全局隔离级别是 读未提交Read Uncommitted) 。

如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。

在这里插入图片描述

SELECT FOR UPDATE 语句的执行会申请 全局锁 ,如果 全局锁 被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是 已提交 的,才返回。

出于总体性能上的考虑,Seata 目前的方案并没有对所有 SELECT 语句都进行代理,仅针对 FOR UPDATE 的 SELECT 语句

结论:
读隔离:如果业务表的更新操存在于分布式事务中,此时本地事务方法中对业务表进行查询操作,建议在本地事务方法上使用@GlobalTransactional+select for update@GlobalLock+select for update注解防止出现数据脏读

注意事项:
使用select for update时需动态传入参数列表,不可使用拼接好的完整字符串查询语句,会导致获取lockKeys为空,引起脏读

五、源码解析

AT 模式下,会使用 Seata 内部数据源代理 DataSourceProxy,我们从提交过程进行调用跟踪:

5.1 使用 @GlobalTransactional

如果执行方法中带有@GlobalTransactional本地事务提交前,先拿到该记录的 全局锁

  • 步骤1️⃣:TM 请求 TC 注册事务分支

io.seata.rm.datasource.ConnectionProxy#getConnection

在这里插入图片描述

io.seata.rm.datasource.ConnectionProxy#doCommit

在这里插入图片描述

io.seata.rm.datasource.ConnectionProxy#processGlobalTransactionCommit

在这里插入图片描述

io.seata.rm.datasource.ConnectionProxy#register

在这里插入图片描述

io.seata.rm.AbstractResourceManager#branchRegister

在这里插入图片描述

至此TM请求TC注册事务分支完成。

  • 步骤2️⃣:TC 注册分支获取全局锁

io.seata.server.coordinator.AbstractCore#branchRegister

在这里插入图片描述

io.seata.server.transaction.at.ATCore#branchSessionLock

在这里插入图片描述

5.2 使用 @GlobalLock

如果执行方法中带有@GlobalLock注解,在提交前会查询 全局锁 是否存在,针对更新select for update等操作时会重试等待,当超出属性lockRetryInterval*lockRetryTimes后抛出Global lock wait timeout异常。

  • 属性值lockRetryInterval覆盖全局配置client.rm.lock.retryInterval校验或占用全局锁重试间隔
  • 属性值lockRetryTimes覆盖全局配置client.rm.lock.retryTimes校验或占用全局锁重试次数`

io.seata.rm.datasource.ConnectionProxy#processLocalCommitWithGlobalLocks

在这里插入图片描述

io.seata.rm.datasource.ConnectionProxy#checkLock

在这里插入图片描述

5.3 @GlobalLock 源码解析

io.seata.spring.annotation.GlobalLock

/**
 * declare the transaction only execute in single local RM
 * but the transaction need to ensure records to update(or select for update) is not in global transaction middle
 * stage
 *
 * use this annotation instead of GlobalTransaction in the situation mentioned above will help performance.
 *
 * @see io.seata.spring.annotation.GlobalTransactionScanner#wrapIfNecessary(Object, String, Object) // the scanner for TM, GlobalLock, and TCC mode
 * @see io.seata.spring.annotation.GlobalTransactionalInterceptor#handleGlobalLock(MethodInvocation, GlobalLock)  // the interceptor of GlobalLock
 * @see io.seata.spring.annotation.datasource.SeataAutoDataSourceProxyAdvice#invoke(MethodInvocation) // the interceptor of GlobalLockLogic and AT/XA mode
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Inherited
public @interface GlobalLock {
    /**
     * customized global lock retry interval(unit: ms)
     * you may use this to override global config of "client.rm.lock.retryInterval"
     * note: 0 or negative number will take no effect(which mean fall back to global config)
     * @return lock retry interval
     */
    int lockRetryInterval() default 0;

    /**
     * customized global lock retry interval(unit: ms)
     * you may use this to override global config of "client.rm.lock.retryInterval"
     * note: 0 or negative number will take no effect(which mean fall back to global config)
     * @return lock retry interval
     */
    @Deprecated
    @AliasFor("lockRetryInterval")
    int lockRetryInternal() default 0;

    /**
     * customized global lock retry times
     * you may use this to override global config of "client.rm.lock.retryTimes"
     * note: negative number will take no effect(which mean fall back to global config)
     * @return lock retry times
     */
    int lockRetryTimes() default -1;

}

源码注释大概含义:

  • 对于某条数据,如果正在 全局事务 中进行更新(或者选择更新)操作,这时某个本地事务需要更新该数据,需要在本地事务方法上使用@GlobalLock注解,确保其不会对全局事务中正在操作的数据造成影响(防止出现脏写)。
  • 声明事务仅在单个本地RM中执行
  • 使用@GlobalLock注解而不是@GlobalTransaction将有助于提高性能
  • 属性值lockRetryInterval覆盖全局配置client.rm.lock.retryInterval校验或占用全局锁重试间隔
  • 属性值lockRetryTimes覆盖全局配置client.rm.lock.retryTimes校验或占用全局锁重试次数`

5.4 SelectForUpdateExecutor 源码解析

io.seata.rm.datasource.exec.ExecuteTemplate#execute

![在这里插入图片描述](https://img-blog.csdnimg.cn/4a999da1ca234b16b47b5ce3aa5d245b.png

io.seata.rm.datasource.exec.SelectForUpdateExecutor#doExecute

在这里插入图片描述

六、下章预告

针对上述理论及源码内容,预计在下个章节进行示例搭建,演示脏读、脏写的产生和对应的修复示例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/547969.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SpringCloud组件——Ribbon(负载均衡)】

一、Ribbon主要作用在哪一环节? 流程讲解: 案例依然采用Eureka章节提供的案例,orderService根据服务名称发起请求,请求传达至Ribbon,此时Ribbon从Eureka中心拉取userService服务列表,Ribbon根据负载均衡算法…

组合预测模型 | ARIMA-WOA-CNN-LSTM时间序列预测(Python)

组合预测模型 | ARIMA-WOA-CNN-LSTM时间序列预测(Python) 目录 组合预测模型 | ARIMA-WOA-CNN-LSTM时间序列预测(Python)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 ARIMA-WOA-CNN-LSTM是一种结合了传统时间序列模型和深…

ChatGPT应用场景巡航之广告文案

此文为ChatGPT应用场景巡航第二篇:广告文案。 写出成功的文案,需要专业的技术水准,如果加以辅助工具,那会更加如虎添翼,事半功倍,本文会给大家介绍一下广告文案的写作技巧和辅助工具的使用。 01 — 指导原…

8-《性能优化》

8-《性能优化》 1 启动优化1.1.冷启动耗时统计?1.2.TraceView和System Trace1.3.优雅获取方法耗时1.4.启动速度优化小技巧1.5.启动优化之异步初始化1.6.启动优化之异步初始化最优解—启动器1.7.延迟初始化1.8.其它方案1.9.启动优化之模拟面试 2 布局优化3 线程优化3…

基于Zynq的雷达10Gbps高速PCIE数据采集卡方案(一)总体设计

2.1 引言 本课题是来源于雷达辐射源识别项目,需要对雷达辐射源中频信号进行采集传输 和存储。本章基于项目需求,介绍采集卡的总体设计方案。采集卡设计包括硬件设计 和软件设计。首先对采集卡的性能和指标进行分析,接着提出硬件的总体设计…

OPCUA 聚合服务器和历史数据服务器

前言 开放自动化是一个热门话题,自动化XML(AutomationML),基于信息模型的通信协议(OPC UA)和工业4.0 管理壳(ASS) 可谓是开放自动化的三套件。三者相互交叉,相互引用&…

教你精通Java语法之第十五章、Lambda表达式

目录 一、背景 1.1Lambda表达式的语法 1.2函数式接口 二、Lambda表达式的基本使用 2.1语法精简 三、变量捕获 3.1匿名内部类 3.2匿名内部类的变量捕获 3.3Lambda的变量捕获 四、Lambda在集合当中的使用 4.1Collection接口 4.2 List接口 4.3Map接口 五、总结 一、背…

2023国赛tomcat题

环境: 10.10.120.128 安装 tomcaA 10.10.120.129 安装tomcatB 10.10.120.130 安装 nginx 配置dns: 正向解析 反向解析 Tomcat ssl配置 [root@localhost ~]# tar -zxvf jdk-11.0.8_linux-x64_bin.tar.gz [root@localhost ~]# mv jdk-11.0.8 /usr/local/ Vim /etc/profile …

如何在代码开发中便捷使用 ChatGPT 协助开发

在五一节前后,抽空测试了下网上推荐的开发环境和开发插件,在这里推荐给前后端代码开发的同胞们。 方法一:IDEA 安装 插件 bito 习惯使用 IDEA 开发代码的同胞,可以尝试直接在 IDEA 中安装插件 bito,注意操作过程中需要…

jarvisoj_fm

小白做题垃圾笔记,不建议阅读。 1.32位操作系统,有canary,和NX ,本来以为是绕过canary呢。 2.第12行,如果x4就执行/bin/sh ,第10行存在格式化字符串漏洞。 是格式化字符串漏洞,对任意地址内容更改。 3.确定…

实操Linux 部署单机版nacos

目录 Nacos部署环境要求JDK安装下载和构建Nocas控制面板,新建配置Nacos数据库配置 总结 Nacos部署环境要求 64bit OS: Linux/Unix/Mac/Windows 支持, Linux/Unix/Mac 推荐 64bit JDK 1.8 Maven 3.2.x JDK安装 1、准备好jdk1.8 链接:https://pan.baidu.…

【SpringCloud组件——Eureka】

前置准备: 分别提供订单系统(OrderService)和用户系统(UserService)。订单系统主要负责订单相关信息的处理,用户系统主要负责用户相关信息的处理。 一、微服务当中的提供者和消费者 1.1、概念 服务提供…

第二章 逻辑分类模型

目录 一、逻辑回归基本模型二、处理多维特征输入三、加载数据集四、多分类问题 一、逻辑回归基本模型 基本模型: y ^ σ ( x ∗ ω b ) \hat{y} \sigma (x * \omega b) y^​σ(x∗ωb),其中 σ ( ) \sigma() σ() 表示 sigmod 函数 σ ( x ) 1 1…

LMS,RGB,XYZ色彩空间转换

前言 首先需要指明本文中描述的R,G,B并非通常的sRGB中的三个分量R,G,B,而是波长分别为700nm,546.1nm,435.8nm的单色红光,单色绿光,单色蓝光。sRGB中的RGB中的红色、绿色、蓝色已经不是单色光了。虽然习惯上大家都叫RGB…

文法的FIRST集

求文法的FIRST集和FOLLOW集的步骤如下: 求FIRST集 如果符号是终结符,则FIRST集合为该终结符本身。如果符号是非终结符,则将该非终结符可以推导出的所有串的FIRST集合合并,得到该非终结符的FIRST集合。如果一个非终结符可以推导出…

Linux篇5

Shell常用命令 1. 磁盘管理类1.1 du:查看文件和目录占用的磁盘空间1.2 df:查看磁盘空间使用情况1.3 free:查看内存使用情况1.4 lsblk:查看设备挂载情况1.5 mount/umount:挂载/卸载1.6 fdisk:分区 2. 进程管…

双模齐下,提质增效:CODING 携手知微共创 BizDevOps 体系新篇章

为了提升工作和管理效率,工具建设是许多企业不得不面对的现实,然而在工具建设落地过程中,往往存在一系列的问题。如不同组织、部门之间互不相通,各自为政,工具流程与实际工作所需不符,导致工具建设的结果是…

(1分钟速览)g2o入门指南--笔记版

在slam后端中,优化的框架很多,有ceres,g2o,gtsam这些。要想真正掌握slam后端的优化内容,这些框架是必不可少的上手练习的内容。本文则介绍有关g2o的相关内容,作为一个入门指南,目标:…

使用教程 | 基于TSMaster如何实现LIN RBS 剩余总线仿真

本文导读 RBS 全称是:residual bus simulation,也就是所谓的剩余总线仿真。主要是基于车载网络数据库,如 CAN/LIN/FlexRay/以太网数据库,仿真该网络内部各个节点的通讯行为。 本文主要讲解 TSMaster 中 LIN RBS 的操作流程。 “ …

aosp11/12/13 壁纸高斯模糊,毛玻璃SurfaceFlinger层面原理-第二节千里马framework实战

hi,粉丝朋友们! 上一个blog已经详细讲解了系统中自带相关接口实现窗口的高斯模糊相关效果,具体点击这里 https://blog.csdn.net/learnframework/article/details/130767893 1、补充app层面实现方式 更多framework干货知识手把手教学 Log.i…