Seata是什么?一文了解其实现原理
一、背景
随着业务发展,单体系统逐渐无法满足业务的需求,分布式架构逐渐成为大型互联网平台首选。伴随而来的问题是,本地事务方案已经无法满足,分布式事务相关规范和框架应运而生。
在这种情况下,大型厂商根据分布式事务实现规范,实现了不同的分布式框架,以简化业务开发者处理分布式事务相关工作,让开发者专注于核心业务开发。
Seata就是这么一个分布式事务处理框架,Seata是由阿里开源,前身为Fescar,经过品牌升级变身Seata。
二、分布式事务规范
1.分布式事务相关概念
事务: 一个程序执行单元,是用户定义的一组操作序列,需要满足ACID属性。
本地事务:事务由本地资源管理器管理。
分布式事务:事务的操作位于不同的节点。
分支事务:在分布式事务中,由资源管理器管理的本地事务。
全局事务:一次性操作多个资源管理器完成的事务,由一组分支事务组成。
2. 分布式事务实现规范
对于本地事务,可以借助DBMS系统来实现事务的管理,但是对于分布式事务,它就无能为力了。对于分布式事务,目前主要有2种思路:XA协议的强一致规范以及柔性事务的最终一致性规范。
2.1 XA
XA是基于2阶段提交协议设计的接口标准,实现了XA规范的资源管理器就可以参与XA全局事务。应用承担事务管理器TM工作,数据库承担资源管理器RM工作,TM生成全局事务id,控制RM的提交和回滚。

2.2 柔性事务的最终一致性
该规范主要有3种实现方式,TCC、MQ事务消息、本地消息表。(还存在其他一些不常用实现方式如Saga)。
TCC:try/confirm/cancel,在try阶段锁定资源,confirm阶段进行提交,资源锁定失败执行cancel阶段释放资源。

MQ事务消息:前提消息系统需要支持事务如RocketMQ,在本地事务执行前,发送事务消息prepare,本地事务执行成功,发送事务消息commit,实现分布式事务最终一致性。如果事务消息commit失败,RocketMQ会回查消息发送者确保消息正常提交,如果步骤5执行失败,进行重试,达到最终一致性。

本地消息表:跟MQ事务消息类似,区别在于MQ不支持事务消息,需要借助本地数据库的事务管理能力。在步骤1中将需要发送的消息和本地事务一起提交到DB,借助DB的事务管理确保消息持久化。步骤2应用通过本地消息表扫描,重试发送,确保消息可以发送成功。

三、Seata 架构
1. 系统组成
Seata有三个核心组件:
- Transaction Coordinator(TC,事务协调器)—— 维护全局事务和分支事务的状态,驱动全局事务提交或回滚。
- Transaction Manager(TM,事务管理器) —— 定义全局事务的范围,开始事务、提交事务、回滚事务。
- Resource Manager(RM,资源管理器):—— 管理分支事务上的资源,向TC注册分支事务,汇报分支事务状态,驱动分支事务的提交或回滚。
三个组件相互协作,TC 以 Server 形式独立部署,TM和RM集成在应用中启动,其整体交互如下:

2.工作模式
Seata 支持四种工作模式:
2.1 AT(Auto Transaction)
AT模式是Seata默认的工作模式。需要基于支持本地 ACID 事务的关系型数据库,Java 应用,通过 JDBC 访问数据库。
2.1.1 整体机制
该模式是XA协议的演变,XA协议是基于资源管理器实现,而AT并不是如此。AT的2个阶段分别是:
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
- 二阶段:提交异步化,非常快速地完成;回滚通过一阶段的回滚日志进行反向补偿。
下图中,步骤1开启全局事务;步骤2注册分支事务,这里对应着一阶段;步骤3提交或者回滚分支事务,对应着二阶段。

2.1.2 特点
- 优点:对代码无侵入;并发度高,本地锁在一阶段就会释放;不需要数据库对XA协议的支持。
- 缺点:只能用在支持ACID的关系型数据库;SQL解析还不能支持全部语法。
2.2 TCC
该模式工作分为三个阶段:
上图中对于多个分支事务,省略了多次出现的 2.* 步骤。对于全局事务执行过程中业务应用宕机情况,业务应用集群中对等节点会通过从TC获取相关会话,从DB加载详细信息来恢复状态机。
2.3.3 特点
- 优点:一阶段提交本地事务,无锁,高性能;事件驱动架构,参与者可异步执行,高吞吐;补偿服务易于实现。
- 缺点:不保证隔离性。
2.4 XA模式
XA是基于二阶段提交设计的接口标准。对于支持XA的资源管理器,借助Seata框架的XA模式,会使XA方案更简单易用。使用前提:需要分支数据库支持XA 事务,应用为 Java应用,且使用JDBC访问数据库。
2.4.1 整体机制
在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。
- 执行阶段:业务sql在XA分支中执行,由分支事务的RM管理器管理,然后执行XA prepare。
- 完成阶段:TM根据各个分支执行结果通过TC通知各个分支执行XA commit或者XA rollback。

2.4.2 特点
- 优点:继承了XA协议的优势,事务具有强一致性。
- 缺点:同样继承了XA协议的劣势,由于分支事务长时间开启,并发度低。
2.5 Seata 各模式对比
分布式事务方案没有银弹,根据自己的业务特性选择合适的模式。例如追求强一致性,可以选择AT和XA,存在和外部系统对接,可以选择Saga模式,不能依赖本地事务,可以采用TCC等等。结合各模式的优缺点进行选择。

四、AT 模式核心实现
鉴于Seata支持的模式较多,而其默认的模式是AT,为节省篇幅,以下围绕AT模式分析其相关的核心模块实现。
1. 事务协调器的启动
TC(事务协调器)以独立的服务启动,作为Server,维护全局事务和分支事务的状态,驱动全局事务提交或回滚。下面是TC的启动流程:

2. 事务管理器的启动
TM(事务管理器)集成在应用中启动,负责定义全局事务的范围,开始事务、提交事务、回滚事务。
TM所在应用中需要配置GlobalTransactionScannerbean,在应用启动时会进行如下初始化流程:

3. 资源管理器的启动
RM(资源管理器)集成在应用中启动,负责管理分支事务上的资源,向TC注册分支事务,汇报分支事务状态,驱动分支事务的提交或回滚。
RM所在的应用中除了需要跟TM一样配置GlobalTransactionScanner以启动RMClient,还需要配置DataSourceProxy,以实现对数据源访问代理。该数据源代理实现了sql的解析 → 生成undo-log → 业务sql和undo-log一并本地提交等操作。
4. 全局事务的工作流程
下面以一个简单的例子来说明全局事务的工作原理:
- BusinessService:发起购买服务
- StorageService:库存管理服务
购买操作实现在businessService.purchase中,purchase方法实现上通过GlobalTransaction注解,通过Dubbo服务,调用了库存服务deduct方法方法,样例如下:
@GlobalTransactional(timeoutMills = 300000, name = "dubbo-demo-tx")
public void purchase(String userId, String commodityCode, int orderCount) {
storageService.deduct(commodityCode, orderCount);
// throw new RuntimeException("xxx");
}
4.1 成功的全局事务处理流程

4.2 成功的全局事务处理流程
这里设定BusinessService在成功调用StorageService后,本地出现异常。

5. 写隔离实现
全局事务未提交,分支事务本地已经提交的情况下(假设修改了资源A),如何避免其他事务在此时修改资源A?Seata采用全局锁来实现,其流程如下:

6. 读隔离实现
在数据库本地隔离级别为读已提交或以上的基础上,Seata提供了读未提交,这个很好理解,全局事务提交前分支事务本地已经提交。如果想要实现读已提交,则需要在select语句上加for update。
五、总结
Seata是Java领域很强大的分布式事务框架,其支持了多种模式。其中默认支持的AT模式,相比于传统的2PC协议(基于数据库的XA协议),很好地解决了2PC长期锁资源的问题,提高了并发度。Seata支持的各个模式中,AT模式对业务零入侵实现分布式事务,对于开发者更加友好。另外Seata的Server在选择合适的存储介质时可以进行集群模式,减少单点故障影响。
本文主要参考官网和部分博客,同时阅读了AT模式实现源码,如果有不对的地方,望指出,一起讨论交流。
六、参考
作者:vivo官网商城开发团队
Seata是什么?一文了解其实现原理的更多相关文章
- 一文说尽 MySQL 优化原理
说起MySQL的查询优化,相信大家收藏了一堆奇技淫巧:不能使用SELECT *.不使用NULL字段.合理创建索引.为字段选择合适的数据类型..... 你是否真的理解这些优化技巧?是否理解其背后的工作原 ...
- 1.1 文档PUT内部原理
文档更新原理: PUT 一条数据的时候,如果是全量替换,ES并不会覆盖原来的文档,而是新创建一个文档,并将version+1,原文档标记为deleted,不会立刻物理删除.ES会在集群的d ...
- MySQL--全文索引作用、原理及使用注意
作用 MySQL索引可以分为:主键索引.普通索引.唯一索引.全文索引.其中,全文索引应该是是比较特殊的,它只有少数的几个存储引擎支持,且只有类型为char.vchar.text的列能建立全文索引.以前 ...
- 【ElasticSearch】文档路由的原理
ElasticSearch集群环境下新增文档如何确认该文档被分配到哪个分片中? 路由算法: ⾸先这肯定不会是随机的,否则将来要获取⽂档的时候我们就不知道从何处寻找了.实际上,这个过程是根据下⾯这个公式 ...
- 文氏电桥振荡电路原理详解及Multisim实例仿真
文氏电桥振荡电路(Wien bridge oscillator circuit),简称"文氏电桥",是一种适于产生正弦波信号的振荡电路之一,此电路振荡稳定且输出波形良好,在较宽的频 ...
- 深度好文,springboot启动原理详细分析
我们开发任何一个Spring Boot项目,都会用到如下的启动类 1 @SpringBootApplication 2 public class Application { 3 public stat ...
- Salesforce学习之路-developer篇(五)一文读懂Aura原理及实战案例分析
1. 什么是Lightning Component框架? Lightning Component框架是一个UI框架,用于为移动和台式设备开发Web应用程序.这是一个单页面Web应用框架,用于为Ligh ...
- 一文搞懂 ThreadLocal 原理
当多线程访问共享可变数据时,涉及到线程间同步的问题,并不是所有时候,都要用到共享数据,所以就需要线程封闭出场了. 数据都被封闭在各自的线程之中,就不需要同步,这种通过将数据封闭在线程中而避免使用同步的 ...
- HTML5(十二)——一文读懂 WebSocket 原理
一.WebSocket 由来 WebSocket 是一个持久化的协议,通过第一次 HTTP Request 建立连接之后,再把通信协议升级成 websocket,保持连接状态,后续的数据交换不需要再重 ...
- 一文搞懂RPC原理
RPC原理解析 什么是RPC RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.R ...
随机推荐
- 【Android】Android Bmob后端云配置
简介 开发一个具有网络功能的应用,在Bmob移动应用云存储平台中,只需要注册一个账号,就可以实现申请创建任意多个数据库,获得对应的key,下载对应版本的SDK,并嵌入到移动应用中,调用存取的KPI,进 ...
- 5分钟搞懂Kubernetes:轻松理解所有组件
之前我曾经提到了一系列关于服务网格的内容.然而,我意识到有些同学可能对Kubernetes的了解相对较少,更不用说应用服务网格这个概念了.因此,今天我决定带着大家快速理解Kubernetes中的一些专 ...
- ubuntu 20.04系统上安装teleport开源堡垒机
ubuntu 20.04安装部署teleport堡垒机 简介:Teleport是一款简单易用的开源堡垒机系统,具有小巧.易用的特点,支持 RDP/SSH/SFTP/Telnet 协议的远程连接和审计管 ...
- NLP项目实战02:英文文本识别
简介: 欢迎来到本篇文章!今天我们将讨论一个新的自然语言处理任务--英文短文识别.具体而言,即通过分析输入的英文文本来判断其是比较消极的还是比较积极的. 展示: 1.项目界面 如下所示是项目启动后用户 ...
- SpringSecurity入门(SSM版)
1. 简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Sp ...
- Odoo16—权限控制
odoo的权限控制是通过用户组来实现的,在用户组中配置控制权限,然后再添加用户到用户组中,从而实现对用户的访问和操作权限控制.一个用户可以属于多个用户组,用户最终的权限范围取决于所属用户组权限的并集. ...
- 在WInform开发中实现工具栏/菜单的动态呈现
在Winform系统开发中,为了对系统的工具栏/菜单进行动态的控制,我们对系统的工具栏/菜单进行动态配置,这样可以把系统的功能弹性发挥到极致.通过动态工具栏/菜单的配置方式,我们可以很容易的为系统新增 ...
- shell中 << EOF 和 EOF 使用
转载请注明出处: EOF(End of File)在Shell中通常用于指示输入的结束,并在脚本或命令中进行多行输入.它允许用户指定一个特定的分界符来表示输入的结束,通常用于创建临时文件.重定向输入或 ...
- 用Roslyn玩转代码之一: 解析与执行字符串表达式
最近框架中的可视化界面设计需要使用到表达式引擎(解析代码字符串并动态执行),之前旧框架的实现是将表达式字符串解析为语法树后解释执行该表达式,本文介绍如何使用Roslyn解析表达式字符串,并直接转换 ...
- echo详解
linux下echo命令详解 linux的echo命令, 在shell编程中极为常用, 在终端下打印变量value的时候也是常常用到的, 因此有必要了解下echo的用法 echo命令的功能是在显示器上 ...