久趣下载站

当前位置: 首页 » 游戏攻略 » Seata原理浅析

Seata原理浅析

前言

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

,但不可能

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

猜你喜欢
本类排行