当前位置: 首页 > news >正文

Spring Cloud系列—Seata分布式事务解决方案AT模式

上篇文章:

Spring Cloud系列—Seata分布式事务解决方案XA模式https://blog.csdn.net/sniper_fandc/article/details/149947291?fromshare=blogdetail&sharetype=blogdetail&sharerId=149947291&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

目录

1 AT模式原理

1.1 整体机制

1.2 写隔离

1.3 读隔离

2 AT模式使用

3 AT模式 VS XA模式


1 AT模式原理

1.1 整体机制

        AT模式是Seata针对两阶段提交2PC的改进模式,是一种非侵入式的分布式事务解决方案。通过引入数据源代理DataSourceProxy,在代理中添加undo_log日志和检查全局锁等逻辑,从而让RM不再需要数据库实现XA协议。改进后的2PC如下:

        一阶段:

        1.注册分支事务:TM开启全局事务,RM向TC注册分支事务;

        2.记录undo_log:执行SQL前首先会解析SQL,根据解析信息记录更新前镜像到undo_log,然后执行SQL记录更新后镜像到undo_log。记录undo_log的目的是因为一阶段会提交本地事务,因此如果要回滚就需要undo_log的支持(2PC需要实现XA协议,如果数据库没有实现该协议,就可能没有写undo日志和redo日志的行为)

        3.提交本地事务和undo_log:提交前获取全局锁(全局事务结束才会释放),然后直接提交本地事务(数据库数据会真实发生变化)。而2PC的一阶段只执行SQL不提交事务,因此2PC一阶段资源还会被锁定,到二阶段执行结束才会释放资源;AT模式在一阶段执行结束就会释放资源。

        4.汇报事务状态:RM向TC汇报本地事务(分支事务)的执行状态。

        二阶段:

        1.提交全局事务:如果所有分支事务都执行成功,则异步执行全局事务的提交和undo_log记录的清除。结束后RM向TC汇报状态,并释放全局锁。

        2.回滚全局事务:如果有分支事务执行失败,则开启本地事务进行回滚。回滚需要查询undo_log并比较当前数据和undo_log更新后镜像数据是否一致(如果不一致说明当前数据被其它全局事务修改,会根据配置策略来处理),如果一致就根据更新前镜像来回滚数据。结束后RM向TC汇报状态,并释放全局锁。

注意:AT模式其实就是在代理层面实现了没有在RM层面实现XA协议的回滚操作相关支持(即undo日志),同时引入全局锁来确保写隔离(不会出现赃写问题)。

1.2 写隔离

        当多线程并发操作同一个数据,就可能出现脏写问题。这是因为AT模式是一阶段就会提交本地事务,在全局事务未提交前,如果其它全局事务的分支事务对该数据修改,最终第一个全局事务提交后,该数据就变为第一个全局事务的值,从而丢失了其它全局事务的值。

        AT模式通过引入全局锁来解决脏写问题,实现写隔离:

        1.一阶段本地事务提交前,需要确保先拿到全局锁。

        2.拿不到全局锁,不能提交本地事务。

        3.拿全局锁的尝试被限制在一定范围内(超时时间或重试次数),超出范围将放弃,并回滚本地事务,释放本地锁。

        tx1全局事务先对m=1000的数据进行修改,本地事务首先要获取该数据的本地锁,执行m-100后为m=900,在提交本地事务前需要先获取全局锁,然后执行本地事务提交,提交成功后释放本地锁。

        tx2全局事务在tx1全局事务的二阶段前开启并执行,执行m-100后m=800(由于tx1一阶段会提交本地事务,因此tx2全局事务会读取m修改后的值),在提交本地事务前需要先获取全局锁,但是由于全局锁在tx1手里,因此就会不断重试获取全局锁。直到tx1事务提交全局事务后,才会释放全局锁,此时tx2才能获取全局锁进行本地事务提交。

        在事务执行成功的情况下,没有全局锁貌似没有问题。但是一旦tx1事务执行失败进行回滚,就会出现脏写。即tx2事务读取的是更新后回滚前的脏数据,tx1一旦回滚,tx2所做的任何操作都会无效。回滚情况下的工作模式如下:

        由于tx2更新后一直无法获取到tx1未释放的全局锁,但是tx2持有本地锁。而tx1想要回滚需要本地锁,但是其未释放全局锁。tx1和tx2就会相互等待,直到tx2获取全局锁超时(或超过重试次数),tx2本地事务就执行失败,进行回滚,并释放本地锁。tx1就能获取全局锁,从而进行回滚。

        总结:全局锁强制将两个阶段原子性执行,从而防止其它全局事务插入到该全局事务的两个阶段之间执行,避免了脏写问题。

1.3 读隔离

        多线程并发读/写,就可能出现脏读问题:即一个事务读到另一个事务读未提交的数据。要解决脏读问题,就需要事务隔离级别是读已提交。

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

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

        通过SELECT FOR UPDATE语句的代理查询tx1事务提交后的数据,该语句会获取全局锁,如果未获取到全局锁,说明事务未提交,就释放本地锁并阻塞等待,阻塞期间不断重试获取全局锁,此时读取的数据就是读已提交的数据,从而避免脏读问题。

        目前,Seata只对SELECT FOR UPDATE语句进行代理,并没有对其它查询语句代理,这是出于性能角度的考虑。

2 AT模式使用

        由于AT模式需要用到undo_log日志,因此需要创建undo_log表:

-- 注意此处0.7.0+ 增加字段 contextCREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

        使用AT模式仅需要修改配置文件:

seata:data-source-proxy-mode: AT

        当库存不足时,全局事务就会执行失败:

3 AT模式 VS XA模式

AT模式

XA模式

实现方式

1.通过记录数据镜像到undo_log日志表的方式来实现回滚

2.不需要数据库支持XA协议,但是需要创建undo_log日志表

1.需要数据库实现XA协议,依赖XA协议实现提交和回滚

2.不需要undo_log表,但是需要数据库支持XA协议

一致性

最终一致性:数据可能处于两阶段之间的中间状态

强一致性:数据的中间状态对用户不可见

性能

性能较好:一阶段直接提交,不锁定资源

性能较差:一阶段锁定资源,二阶段结束才释放

代码入侵

无代码入侵

无代码入侵

数据库支持

适用于几乎所有支持SQL的数据库

适用于实现XA协议的数据库

适用场景

性能要求高并且接受最终一致性场景

要求强一致性并且性能要求不高场景

下篇文章:

http://www.dtcms.com/a/339702.html

相关文章:

  • 2025年6月中国电子学会青少年软件编程(图形化)等级考试试卷(一级)答案 + 解析
  • 编译器错误消息: CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET... 拒绝访问
  • Linux管道
  • NVIDIA 优化框架:Jetson 平台 PyTorch 安装指南
  • 初步学习WPF-Prism
  • 图论\dp 两题
  • GIS相关调研
  • Meta首款AR眼镜Hypernova呼之欲出,苹果/微美全息投入显著抢滩市场新增长点!
  • MyBatis-Plus基础篇详解
  • HashMap工作原理
  • 使用Tomcat Clustering和Redis Session Manager实现Session共享
  • 设备树下的LED驱动实验
  • 【机器人】2025年人形机器人时代:伦理迷雾中的人类界限
  • PAT 1072 Gas Station
  • visionpro获取电脑cpu序列号
  • 生信分析自学攻略 | R语言数据类型和数据结构
  • 矿物分类系统开发笔记(二):模型训练[删除空缺行]
  • leetcode2248. 多个数组求交集
  • ES支持哪些数据类型,和MySQL之间的映射关系是怎么样的?
  • Vue3 学习教程,从入门到精通,vue3综合案例:“豪华版”待办事项(41)
  • [Polly智能维护网络] 网络重试原理 | 弹性策略
  • PyTorch数据处理工具箱(utils.data简介)
  • UE5 PCG 笔记(一)
  • C++ STL(标准模板库)学习
  • 华为鸿蒙系统SSH如何通过私钥连接登录
  • 传统概率信息检索模型:理论基础、演进与局限
  • 短剧小程序系统开发:打造沉浸式短剧观影体验
  • EPM240T100I5N Altera FPGA MAX II CPLD
  • Spring Cache 整合 Redis 实现高效缓存
  • idea如何设置tab为4个空格