问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Seata原理浅析

创作时间:
作者:
@小白创作中心

Seata原理浅析

引用
1
来源
1.
https://www.cnblogs.com/fuxing/p/18186136

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 的指令,进行统一的提交或回滚操作。
  3. 提交时,异步删除相应分支的 undo log;
  4. 回滚时,根据 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
,但不可能
Confirm

Cancel
,这就是业务悬挂,需要避免空回滚后的
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. 需要考虑
    Confirm

    Cancel
    的失败情况,做好幂等处理。

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从入门到进阶.

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号