前言

Seata是阿里开源的分布式事务解决方案,本文将详细介绍 Seata 的事务模式、原理以及使用。了解之前需清楚什么是分布式事务


一、什么是 Seata

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了XA、AT、TCC 和 SAGA 事务模式,为用户打造一站式的分布式解决方案。

Seata 的几种角色:

角色 说明
TC Transaction Coordinator,事务协调者,用来协调全局和各个分支事务(不同服务)的状态, 驱动它们的回滚或提交。
TM Transaction Manager,事务管理者,业务层中用来开启/提交/回滚一个整体事务(在调用服务的方法中用注解开启事务)。
RM Resource Manager,资源管理者,管理分支事务,与 TC 进行协调注册分支事务,并且汇报分支事务的状态,驱动分支事务的提交或回滚。

简单流程图:

二、事务模式

1. XA 模式

Seata 的 XA 模式大体与 2PC 事务相似。

1.1 流程介绍

第一阶段:

  1. RM 注册分支事务到 TC;
  2. RM 执行分支业务的 SQL 但不提交
  3. RM 报告执行状态到 TC;

第二阶段:

  1. TC 检测检测各分支事务状态,判断整体事务提交或回滚;
  2. RM 接受 TC 的指令,进行统一的提交或回滚操作。

1.2 XA 优缺点

优点:

  1. 事务强一致性,满足 ACID 原则;
  2. 实现简单,无代码入侵。

缺点:

  1. 一阶段锁定资源,二阶段结束才释放,性能较差;
  2. 依赖关系型数据库实现事务;

2. AT 模式

Auto Transaction,基于 XA 演进而来,需要数据库支持,如果是 MySQL,则需要5.6以上版本才支持XA协议。

是一种无侵入的分布式事务解决方案,该模式下,用户只需关注自己的业务 SQL,Seata 框架会在第一阶段拦截并解析 SQL,生成 undo log,并自动生成事务二阶段的提交和回滚操作。

AT 模式下,是利用快照实现数据回滚,属于弱一致。

2.1 流程介绍

第一阶段:

  1. RM 注册分支事务到 TC;
  2. 记录 undo log(数据快照);
  3. RM 执行分支业务的 SQL 并提交
  4. RM 报告执行状态到 TC;

第二阶段:

  1. TC 检测检测各分支事务状态,判断整体事务提交或回滚;
  2. RM 接受 TC 的指令,进行统一的提交或回滚操作。
    1. 提交时,异步删除相应分支的 undo log;
    2. 回滚时,根据 undo log 生成补偿回滚的 SQL,执行分支回滚并返回结果给 TC;

例如,一个分支业务需要对account余额表中的money进行扣减 10 元,则需要进行如下流程:

2.2 脏写问题

如下图所示,并发事务之间,可能会产生脏写导致数据修改被覆盖。

如何解决脏写,Seata 通过全局锁来管理事务,持有全局锁的事务才有执行 SQL 的权利,这里全局锁只针对交由 Seata 管理的事务

如下图,简单流程大致如下:

  1. 一阶段本地事务提交前,需要确保先拿到全局锁 ;
  2. 拿不到全局锁 ,不能提交本地事务。
  3. 拿不到全局锁会重试,次数有限,超出限制将放弃,并回滚本地事务,释放本地锁。

2.3 数据快照

那么非 Seata 事务于 Seata 事务并发修改数据时如何处理?

RM 在第一阶段将分支事务注册到 TC 时,会在 undo log 保存两个数据快照,分别是:

  • before-image:数据修改前的快照
  • after-image:数据修改后的快照

当发生异常时,before-image用来做数据回滚,after-image来判断修改后数据于当前数据是否相同,相同则通过before-image做数据回滚,不同则说明被其他非 Seata 事务修改过,记录异常,人工介入。

具体流程见下图。

2.4 脏读问题

与脏写类似,是指在全局事务未提交前,被其它业务读到已提交的分支事务的数据,本质上 Seata 默认的全局事务是读未提交

那么怎么避免脏读现象呢?

  1. 业务查询时要使用@GlobalTransactional@GlobalLock来修饰查询方法的调用;
  2. 查询语句须使用select for update语句。

这样在执行 SQL 前会检查全局锁是否存在,只有当全局锁完成之后,才能继续执行 SQL,这样就防止了脏读。

不过,AT 事务模式下读已提交的成本很高,对于非必要场景还是要尽量避免使用。

传统的读已提交不需要本地锁,但这里却需要select for update语句,查询多出了加锁和竞争的开销,另外还要持锁调用 TC 的lockQuery接口以判断全局锁情况。

2.5 AT 优缺点

优点:

  1. 一阶段直接完成事务提交,释放数据库资源,性能比较好;
  2. 利用全局锁实现读写隔离;
  3. 没有代码入侵,框架自动完成回滚或提交。

缺点:

  1. 两阶段之间属于软状态,属于最终一直;
  2. 数据快照会影响性能,但比 XA 模式要好很多;

3. TCC 模式

关于什么是 TCC 模式及原理,详情见什么是分布式事务

TCC 与 AT 模式很相似,每阶段都是独立事务,不同的是 TCC 通过人工编码来实现数据恢复。

3.1 流程介绍

TCC 每个阶段是做什么的:

  1. Try:资源的检测和预留;
  2. Confirm:完成资源操作业务,要求Try成功,Confirm一定能成功;
  3. Cancel:预留资源释放,可以理解为Try的反向操作。

TCC 不存在资源阻塞的问题,因为每个方法都直接进行事务的提交,一旦出现异常通过则Cancel来进行回滚补偿,这也就是常说的补偿性事务

举例,一个扣减用户愈合的业务,假设账户 A 原来的余额是 100,需要扣减 30 元。

空回滚和业务悬挂

什么是空回滚?

分支事务Try操作阻塞时,可能导致全局事务超时触发Cancel操作。在Try未执行时先执行了Cancel,这时的Cancel理论上不应该回滚,这时就需要空回滚

什么是业务悬挂?

对于已经空回滚的业务,这时如果线程不再阻塞,继续执行Try,但不可能ConfirmCancel,这就是业务悬挂,需要避免空回滚后的Try操作。

如何解决空回滚和业务悬挂?

回滚时需要在执行Cancel操作时,判断有没有执行Try操作。相应的,在执行Try时判断有没有该事务是否回滚过。

这里,我们假设需要在冻结金额的时候进行事务操作。为了实现空回滚,防止业务悬挂,以及幂等性要求。我们必须在数据库记录冻结金额的同时,记录当前事务 ID 和执行状态,冻结金额表如下设计:

CREATE TABLE 'account_freeze_tbl'(
'xid' varchar (128) NOT NULL,
'user_id' varchar(255) DEFAULT NULL COMMENT '用户id',
'freeze_money' int(11) unsigned DEFAULT '0' COMMENT '冻结金额',
'state' int(1) DEFAULT NULL COMMENT '事务状态, O:try, 1:confirm, 2:cancel',
PRIMARY KEY ('xid') USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

表字段设计完成后,执行如下的业务逻辑即可避免空回滚和业务悬挂。

3.2 TCC 优缺点

优点:

  1. 一阶段直接完成事务提交,释放数据库资源,性能比较好;
  2. 相比 AT,无需生成快照和使用全局锁,性能最好;
  3. 不依赖数据库事务,依赖补偿操作,可用于非事务型数据库。

缺点:

  1. 代码入侵,每个阶段都需要编写对应的业务代码;
  2. 软状态,属于最终一致;
  3. 需要考虑ConfirmCancel的失败情况,做好幂等处理。

4. Saga 模式

关于什么是 Saga 模式及原理,详情见什么是分布式事务

Saga 模式是 Seata 提供的长事务解决方案。也分为两个阶段:

  • 一阶段: 直接提交本地事务
  • 二阶段: 成功则什么都不做;失败则通过编写补偿业务来回滚

优点:

  1. 事务参与者可以基于事件驱动实现异步调用,吞吐高;
  2. 一阶段直接提交本地事务,无锁,性能好;
  3. 代码入侵较 TCC 低,实现简单。

缺点:

  1. 软状态持续时间不确定,时效性差;
  2. 没有锁和事务隔离,可能会有脏写。

三、代码实现

具体代码使用,可参考 Seata 官方文档

这里需要注意每个模式需要的准备工作不同,如AT模式下就需要准备如下几点:

  1. lock_table 导入 Seata 数据库,就是 TC 服务关联的数据库;
  2. undo_log 导入业务相关的数据库;
  3. 修改事务模式。

四、对比总结

对比维度 XA AT TCC Saga
数据一致性 强一致性 弱一致性 最终一致性 最终一致性
隔离性 完全隔离 基于全局锁 基于资源预留 无隔离
代码入侵
性能 较低
依赖本地事务 依赖 依赖 不依赖 不依赖
场景 一致性,隔离性要求高的业务场景。 继续关系型数据库的大多分布式事务的场景均适合。 对性能要求高,且有非关系型数据库参与的事务。 业务流程较长,数据时效性要求较低的场景。

参考:

[1] B站黑马. Seata从入门到进阶.

Seata原理浅析的更多相关文章

  1. HTTP长连接和短连接原理浅析

    原文出自:HTTP长连接和短连接原理浅析

  2. Javascript自执行匿名函数(function() { })()的原理浅析

    匿名函数就是没有函数名的函数.这篇文章主要介绍了Javascript自执行匿名函数(function() { })()的原理浅析的相关资料,需要的朋友可以参考下 函数是JavaScript中最灵活的一 ...

  3. [转帖]Git数据存储的原理浅析

    Git数据存储的原理浅析 https://segmentfault.com/a/1190000016320008   写作背景 进来在闲暇的时间里在看一些关系P2P网络的拓扑发现的内容,重点关注了Ma ...

  4. Android-Binder原理浅析

    Android-Binder原理浅析 学习自 <Android开发艺术探索> 写在前头 在上一章,我们简单的了解了一下Binder并且通过 AIDL完成了一个IPC的DEMO.你可能会好奇 ...

  5. Dubbo学习(一) Dubbo原理浅析

    一.初入Dubbo Dubbo学习文档: http://dubbo.incubator.apache.org/books/dubbo-user-book/ http://dubbo.incubator ...

  6. 沉淀,再出发:docker的原理浅析

    沉淀,再出发:docker的原理浅析 一.前言 在我们使用docker的时候,很多情况下我们对于一些概念的理解是停留在名称和用法的地步,如果更进一步理解了docker的本质,我们的技术一定会有质的进步 ...

  7. 阻塞和唤醒线程——LockSupport功能简介及原理浅析

    目录 1.LockSupport功能简介 1.1 使用wait,notify阻塞唤醒线程 1.2 使用LockSupport阻塞唤醒线程 2. LockSupport的其他特色 2.1 可以先唤醒线程 ...

  8. 【Spark Core】TaskScheduler源代码与任务提交原理浅析2

    引言 上一节<TaskScheduler源代码与任务提交原理浅析1>介绍了TaskScheduler的创建过程,在这一节中,我将承接<Stage生成和Stage源代码浅析>中的 ...

  9. vue的双向绑定原理浅析与简单实现

    很久之前看过vue的一些原理,对其中的双向绑定原理也有一定程度上的了解,只是最近才在项目上使用vue,这才决定好好了解下vue的实现原理,因此这里对vue的双向绑定原理进行浅析,并做一个简单的实现. ...

  10. 消息队列——ActiveMQ使用及原理浅析

    文章目录 引言 正文 一.ActiveMQ是如何产生的? 产生背景 JMS规范 基本概念 JMS体系结构 二.如何使用? 基本功能 消息传递 P2P pub/sub 持久订阅 消息传递的可靠性 事务型 ...

随机推荐

  1. 攻防世界 Replace Reverse二星题

    解题过程中,虽然解出来了,但是磕磕绊绊犯了一些错误,记录一下 分析过程 PE查壳 有一个upx壳,最下面给了脱壳提示: upx.exe -d Replace.exe 脱壳结束,丢到IDA里,SHIF+ ...

  2. PWA 实践/应用(Google Workbox)

    桌面端 PWA 应用: 移动端添加到桌面: 1 什么是 PWA PWA(Progressive Web App - 渐进式网页应用)是一种理念,由 Google Chrome 在 2015 年提出.P ...

  3. Mybatis实现增删改查

    ​1.CRUD 1.1namespace namespace中的包名必须和Dao/mapper接口包名一致 1.2select 选择,查询语句 id:就是对应的namespace中的方法名 resul ...

  4. DevEco Studio 3.1 Beta新特性知多少

     原文链接:https://mp.weixin.qq.com/s/HYdNlKKA9Z51dfI1bcplDA,点击链接查看更多技术内容: DevEco Studio 3.1 Beta新特性知多少原文 ...

  5. 【直播预告】HarmonyOS极客松赋能直播第四期:HarmonyOS开发经验分享

  6. 【VMware vCenter】使用Reduced Downtime Update (RDU)升级更新vCenter Server。

    Reduced Downtime Upgrade (RDU) 减少停机时间更新是用于vCenter Server更新升级的一种新的方式,顾名思义,主要目的就是为了减少在vCenter Server更新 ...

  7. leetcode:1381. 设计一个支持增量操作的栈

    1381. 设计一个支持增量操作的栈 请你设计一个支持下述操作的栈. 实现自定义栈类 CustomStack : CustomStack(int maxSize):用 maxSize 初始化对象,ma ...

  8. 调用App Store Connect Api

    对iOS的证书.描述文件.账号.设备等管理,之前都去苹果开发者中心操作,官网上操作也比较繁杂,想搞一些自动化之类的,更是麻烦,有时候官网都打不开-- 其实苹果还提供里一套API接口,创建证书.创建账号 ...

  9. 深入解析Rivest Cipher 4:理论与实践

    第一章:引言 密码学简介: 密码学是研究如何保护通信和信息安全的学科.它涉及加密算法.解密算法.密钥管理等内容,旨在确保信息在传输和存储过程中不被未经授权的人所获取或篡改.密码学可以分为对称加密和非对 ...

  10. eclipse jar包 Source not found

    jar包 Source not found 错误内容: Source not found The source attachment does not contain the source for t ...