聊聊Seata分布式解决方案AT模式的实现原理
什么是Seata分布式事务解决方案
Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式解决方案。
AT模式
AT模式目前来看是Seata框架独有的一种模式,其它的分布式框架上并没有此种模式的实现。其是由二阶段提交演变来的,解决了二阶段提交的同步阻塞等问题。
演变后的两阶段提交协议:
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
- 二阶段:
- 提交异步化,非常快速地完成。
- 回滚通过一阶段的回滚日志进行反向补偿。
Seata框架中有三个概念要阐述下。
- TC:事务协调器,它是独立的组件,需要独立部署运行,Seata提供了这个独立运行的程序,它负责维护全局事务的运行状态,接收TM指令发起全局事务的提交与回滚,负责与RM通信,协调各个分支事务的提交或回滚。
- TM:事务管理器,TM需要嵌入应用程序,它负责开启一个全局事务,并定义全局事务的范围,它的目的是最终向TC发起全局提交或回滚指令。
- RM:与TC通信,控制分支事务,负责分支注册、报告分支事务状态,并接收事务协调器TC的指令,命令分支事务完成本地事务的提交或回滚。
流程示意图如下:
这个图还是比较清晰地,建议是先好好的理解下全流程。
Seata AT模式的具体流程如下。
(1)订单服务收到请求,订单服务中的TM向TC申请开启一个全局事务。(2)TC收到请求,创建一个全局事务,并将全局事务ID(称为XID)返回给订单服务的TM。
(3)订单服务的RM向TC注册分支事务。
(4)订单服务执行本地分支事务的业务逻辑并提交,释放锁定的数据库资源。
(5)订单服务向TC上报本地分支事务的提交结果。
(6)订单服务调用远程的积分服务,此时将XID通过参数传给积分服务。(7)积分服务向TC注册分支事务。
(8)积分服务执行本地分支事务的业务逻辑并提交,释放锁定的数据库资源,并返回订单服务。
(9)积分服务向TC上报本地分支事务的提交结果。
(10)订单服务的TM向TC发起全局事务的提交或回滚。
(11)TC向XID管辖下的全部分支事务发出提交或回滚的指令。
实现原理
我个人觉得框架其实也是一种需求的兑现,只是不像平常开发时那样有产品经理给你输出需求文档(应该也会有,但是少),业务流程不是传统的那种XXX业务,框架的需求一般是偏向技术一些,我把它认为是技术需求;而日常我们做的开发一般是业务需求的兑现。
上面的流程可以看作是需求,那么现在需求出来了,程序猿要怎么实现?
设计思路
TM的设计
流程的开始与结束是由TM决定的,这个TM就是订单服务Controller入口进去后的某个Service方法(当然也可能不是,看你的代码架构,我这里只按照我自己的平常的开发模式来。)在这个Service方法中,处理了订单服务以及积分服务的业务。当Service方法完成后,那么就是整个业务做完了,事务即完成。因此,要我来实现,这个TM对应的Service方法,我会选择用一个注解包裹,通过动态代理的方式,在这个方法的前后分别负责全局事务的开始与结束流程。
RM的设计
RM负责执行具体的业务,将数据入库同时上报给TC。由于二阶段回滚时需要根据回滚日志replay,那么就一定需要记录业务数据执行的日志。那怎么记录?回想了下Mybatis中的数据源代理,这里也是一样的思路。必须拦截或是代理原先的数据源,解析原执行的sql,注入Seata的逻辑,增强其执行逻辑。我们看下RM要做的事情,第一阶段:
第二阶段提交:
第二阶段回滚:
在执行sql的过程中,各个代理对象起到的作用如下
所以在RM端最关键的就是数据源代理以及远程通信。这两块尤其是前者,就是AT模式的技术实现。
TC的设计
TC端需要管理Seata全局事务会话信息,一般是由全局事务、分支事务、全局锁构成,对应表globaltable、branchtable、lock_table。因此在安装部署的时候(file模式除外)都会创建这三个表。从上面来看,目前我们还没有实现隔离性,所谓的隔离性是指多个用户并发访问数据库时,数据库为每个用户开启的事务不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。这也是这里有一个全局锁表的原因。每次本地事务提交前,都会向TC端申请注册分支,同时还会申请全局锁,RM端通过拿到的全局锁保证了读写的隔离性,因此一旦当前事务持有全局锁,那么其他的事务不能提交。
写隔离
两个全局事务 tx1 和 tx2,分别对 a 表的 m 字段进行更新操作,m 的初始值 1000。
- tx1 先开始,开启本地事务,拿到本地锁,更新操作 m = 1000 - 100 = 900。本地事务提交前,先拿到该记录的全局锁 ,本地提交释放本地锁。
- tx2 后开始,开启本地事务,拿到本地锁,更新操作 m = 900 - 100 = 800。本地事务提交前,尝试拿该记录的全局锁,tx1 全局提交前,该记录的全局锁被 tx1 持有,tx2 需要重试等待全局锁。
- tx1 二阶段全局提交,释放全局锁。tx2 拿到全局锁提交本地事务。
如果 tx1 的二阶段全局回滚,则 tx1 需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。
此时,如果 tx2 仍在等待该数据的全局锁,同时持有本地锁,则 tx1 的分支回滚会失败。分支的回滚会一直重试,直到 tx2 的全局锁等锁超时,放弃全局锁并回滚本地事务释放本地锁,tx1 的分支回滚最终成功。
因为整个过程全局锁在 tx1 结束前一直是被 tx1 持有的,所以不会发生脏写的问题。
读隔离
seata at 模式默认的隔离级别为读未提交(因为已经提交的sql有可能会回滚)。如果要实现读已提交,select语句需要更改为 SELECT FOR UPDATE 语句。
SELECT FOR UPDATE 语句的执行会申请全局锁,如果全局锁被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是已提交的,才返回。
总结
Seata AT可以给你带来一种“无侵入”式的编程体验,你不需要改动任何业务代码,只需要一个注解和少量的配置信息,就可以实现分布式事务。
总结来看,AT模式主要是是基于 DataSource 代理实现的,通过代理 DataSource、Connection、PreparedStatement,拦截 SQL 执行,增强其执行逻辑,由代理侧加入额外的能力以提供分布式事务服务类似自动挡驾驶模式,分布式事务这个强大且复杂的服务能力由Seata框架托管,对业务实现无侵入式,用户仍然只专注于业务 SQL。
聊聊Seata分布式解决方案AT模式的实现原理的更多相关文章
- Dubbo学习系列之十四(Seata分布式事务方案AT模式)
一直说写有关最新技术的文章,但前面似乎都有点偏了,只能说算主流技术,今天这个主题,我觉得应该名副其实.分布式微服务的深水区并不是单个微服务的设计,而是服务间的数据一致性问题!解决了这个问题,才算是把分 ...
- 微服务痛点-基于Dubbo + Seata的分布式事务(AT)模式
前言 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案. ...
- 微服务痛点-基于Dubbo + Seata的分布式事务(TCC模式)
前言 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案. ...
- 【深入浅出Seata原理及实战】「入门基础专题」探索Seata服务的AT模式下的分布式开发实战指南(2)
承接上文 上一篇文章说到了Seata 为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案.那么接下来我们将要针对于AT模式下进行分布式事务开发的原理进行介绍以及 ...
- Dubbo学习系列之十五(Seata分布式事务方案TCC模式)
上篇的续集. 工具: Idea201902/JDK11/Gradle5.6.2/Mysql8.0.11/Lombok0.27/Postman7.5.0/SpringBoot2.1.9/Nacos1.1 ...
- SpringCloud微服务实战——搭建企业级开发框架(二十七):集成多数据源+Seata分布式事务+读写分离+分库分表
读写分离:为了确保数据库产品的稳定性,很多数据库拥有双机热备功能.也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器:第二台数据库服务器,主要进行读的操作. 目前有多种方式实现读写分离,一种 ...
- 5-4 Seata 分布式事务管理
下载Seata https://github.com/seata/seata/releases https://github.com/seata/seata/releases/download/v1. ...
- SpringCloud Alibaba(六) - Seata 分布式事务锁
1.Seata 简介 1.1 Seata是什么 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事 ...
- 【深入浅出Seata原理及实战】「入门基础专题」带你透析认识Seata分布式事务服务的原理和流程(1)
分布式事务的背景 随着业务的不断发展,单体架构已经无法满足我们的需求,分布式微服务架构逐渐成为大型互联网平台的首选,但所有使用分布式微服务架构的应用都必须面临一个十分棘手的问题,那就是"分布 ...
- Seata分布式事务
使用Seata版本:1.6.1(2023/2/6最新版)该版本存在很多坑,相较于1.0版本,配置上存在很多差别,如果你的版本不同,请不要参考本文. 1.6.1配置存在许多问题,比较难找,如果你使用1. ...
随机推荐
- Android笔记--FileProvider
FileProvider介绍 继承于ContentProvider,本质上依旧是用于跨境通信,对第三方应用暴露文件,并授予文件读写地权限 具体内容 1.在Strings.xml里面配置一个常量 2.在 ...
- Google Protobuf 编解码
更多内容,前往个人博客 Protobuf 全称:Google Protocol Buffers,由谷歌开源而来,经谷歌内部测试使用.它将数据结构以 .proto 文件进行描述,通过代码生成工具可以生成 ...
- Mybatis Plus根据某字段特定值排序
需求 背景:一个审核流程.审核人等级分为市级和省级,管理员升级字段adminlevel,字段含义:1省级,2市级.审核字段audit为int字段,字段含义:1待市级审核,2待省级审核,3通过审核. 需 ...
- UnrealEngine - 反射系统分析
1. 反射 什么是反射?或者说反射能做什么,简单来说,反射可以提供一种能力,能够在运行时动态获取对象的成员信息,如成员函数,成员变量. UE 在其反射系统上支持了许多功能,如: 编辑器中可供编辑的属性 ...
- 二进制安装Kubernetes(k8s) v1.24.0 IPv4/IPv6双栈 (三主俩从)
二进制安装Kubernetes(k8s) v1.24.0 IPv4/IPv6双栈 (三主俩从) Kubernetes 开源不易,帮忙点个star,谢谢了 介绍 kubernetes二进制安装 后续尽可 ...
- 关于 IDP 的五大认知误解
内部开发者平台(IDP)是近年来在希望加快软件交付和改善开发者体验的企业中得到普及的一个概念.然而,大众对于什么是 IDP 以及它能为开发者和企业带来什么也有很多困惑和误解.在这篇文章中,我们将尝试解 ...
- Python程序笔记20230306
判断闰年 初始版本 year = input('请输入一个年份:') while not year.isdigit(): year = input("抱歉,您的输入有误,请输入一个整数:&q ...
- AspNetCore 成长杂记(一):JWT授权鉴权之生成JWT(其一)
引子 最近不知怎么的,自从学了WebAPI(为什么是这个,而不是MVC,还不是因为MVC的Razor语法比较难学,生态不如现有的Vue等框架,webapi很好的结合了前端生态)以后,使用别人的组件一帆 ...
- 3.2 构造器、this、包机制、访问修饰符、封装
构造器 构造器:在实例化的一个对象的时候会给对象赋予初始值,因此我们可以通过修改构造器,来改变对象的初始值,构造器是完成对象的初始化,并不是创建对象 我们也可以创建多个构造器实现不同的初始化,即构造器 ...
- Qt第三方库QtAV--- ubuntu编译与运行
Qt第三方库QtAV--- ubuntu编译与运行 今天又要接触这个,把一些错误或者不足的地方重新补充下!!!由于前面一段时间,项目中需要借助QtAV接口进行视频播放,特此记录下整个配置过程.整个代码 ...