Seata 的4种事务模式(XA、AT、TCC、SAGA)

目录

前言

Seata架构

事务模式

XA

AT

TCC

区别


前言

在分布式系统中,实现一个功能可能需要由几个不同的服务来共同实现。这就会带来一个问题,不同的服务之间无法做到使用同一个事务,这就无法保证数据的一致性了。在一些对数据一致性要求不要的业务场景中,可以基于本地消息表来实现分布式事务,只需要保证最终一致性就行了。

基于本地消息表实现分布式事务(最终一致性)_本地消息表处理分布式事务-CSDN博客文章浏览阅读1k次,点赞33次,收藏11次。传统单体架构下,所有的功能模块都在一个应用下,所有的代码和业务逻辑都在同一个应用下实现,所以保证数据的一致性就很简单,保证相关操作都在同一个本地事务下就可以了。但是在微服务架构下,将一个应用拆分成了多个独立的服务,每个服务都能有自己的数据库,服务间通信都是通过远程调用实现,实现一个功能可能需要由几个不同的服务来共同实现。这就会带来一个问题,不同的服务之间无法做到使用同一个事务,这就无法保证数据的一致性了。_本地消息表处理分布式事务https://blog.csdn.net/typeracer/article/details/140998899但是也存在一些需要强一致性的业务场景,实际工作中开发过一个事件设计器,设计器中支持各种业务节点,对节点进行编排从而来自定义业务逻辑。不同的节点的实现需要调用不同的服务来实现,故存在分布式事务的问题。对各个节点的服务调用,需要保证所有事务的原子性,要么一起提交,要么一起回滚,所以最后通过引入Seata来解决

在学习 Seata 时,对各种事务模式都做了了解,对比后才能为系统选择最合适的事务模式。在事件设计器中,由于业务对实时性要求不高,所以直接使用XA模式,集成最简单,没有代码侵入。

Seata架构

  • TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
  • TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
  • RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

分布式事务基本流程

事务模式

  1. XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
  2. AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
  3. TCC模式:最终一致的分阶段事务模式,有业务侵入
  4. SAGA模式:长事务模式,有业务侵入

XA

plantuml

@startuml
'https://plantuml.com/sequence-diagram

autonumber 1.1

participant TM
participant RM
participant TC

TM -> TC: 开启全局事务
TM <-- TC: XID
TM -> RM: 远程调用 XID
RM -> TC: 注册分支事务
RM -> RM: 执行业务sql
RM -> TC: 报告分支事务状态

autonumber inc A

TM -> TC: 提交/回滚全局事务
TC -> TC: 检查分支事务状态
RM <- TC: 提交/回滚

@enduml

优点

  • 事务的强一致性,满足ACID原则。
  • 常用数据库都支持,实现简单,并且没有代码侵入

缺点

  • 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
  • 依赖关系型数据库实现事务

AT

AT模式是Seata的默认事务模式

在使用前,需要在对应的业务库中创建一张 undo_log 表,用来保存快照

建表语句(MySQL)

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

流程图

plantuml

@startuml
'https://plantuml.com/sequence-diagram

autonumber 1.1

database undo_log
participant TM
participant RM
participant TC

TM -> TC: 开启全局事务
TM <-- TC: XID
TM -> RM: 远程调用 XID
RM -> TC: 注册分支事务
RM -> RM: 执行业务sql并提交
undo_log <- RM: 记录更新前后快照
RM -> TC: 报告分支事务状态

autonumber inc A

TM -> TC: 提交/回滚全局事务
TC -> TC: 检查分支事务状态
RM <- TC: 提交/回滚
undo_log <- RM: 删除log/回复log数据

@enduml

优点

  • 一阶段完成直接提交事务,释放数据库资源,性能比较好
  • 没有代码侵入,框架自动完成回滚和提交

缺点

  • 软状态,事务是最终一致
  • 框架的快照功能会影响性能,但比XA模式要好很多

TCC

 TCC模式将事务拆成了三个接口实现(try,commit,cancel),同时也带来了以下三个问题

  1. 幂等:在 commit/cancel 阶段,因为 TC 没有收到分支事务的响应,需要进行重试,这就要分支事务支持幂等
  2. 空回滚:在 try 阶段发生了故障,try 阶段在不考虑重试的情况下,全局事务必须要走向结束状态,这样就需要执行一次 cancel 操作
  3. 悬挂:因为网络问题,RM 开始没有收到 try 指令,但是执行了 cancel 后 RM 又收到了 try 指令并且预留资源成功,这时全局事务已经结束,最终导致预留的资源不能释放

在1.5.1以前,这些问题需要自己在代码中解决,而1.5.1版本以后(包含1.5.1),Seata就自己解决这些问题了

需要在对应的业务库中创建一张 tcc_fence_log 表

建表语句(MySQL)

CREATE TABLE IF NOT EXISTS `tcc_fence_log`
(
    `xid`           VARCHAR(128)  NOT NULL COMMENT 'global id',
    `branch_id`     BIGINT        NOT NULL COMMENT 'branch id',
    `action_name`   VARCHAR(64)   NOT NULL COMMENT 'action name',
    `status`        TINYINT       NOT NULL COMMENT 'status(tried:1;committed:2;rollbacked:3;suspended:4)',
    `gmt_create`    DATETIME(3)   NOT NULL COMMENT 'create time',
    `gmt_modified`  DATETIME(3)   NOT NULL COMMENT 'update time',
    PRIMARY KEY (`xid`, `branch_id`),
    KEY `idx_gmt_modified` (`gmt_modified`),
    KEY `idx_status` (`status`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

流程图

plantuml

@startuml
'https://plantuml.com/sequence-diagram

autonumber 1.1

database tcc_fence_log
participant TM
participant RM
participant TC

TM -> TC: 开启全局事务
TM <-- TC: XID
TM -> RM: 远程调用 XID
RM -> TC: 注册分支事务
RM -> RM: 锁定资源(try)
tcc_fence_log <- RM: 插入防空回滚记录
note left
    插入一条记录
    status值为STATUS_TRIED
    在 Rollback 阶段判断记录是否存在
    如果不存在,则不执行回滚操作
end note
RM -> TC: 报告分支事务状态

autonumber inc A

TM -> TC: 提交/回滚全局事务
TC -> TC: 检查分支事务状态
RM <- TC: 提交/回滚

tcc_fence_log <- RM: 幂等判断
note left
    判断 tcc_fence_log 表中是否已经有记录
    如果有记录,则判断事务执行状态是否为 STATUS_COMMITTED
    是的话就不会再次提交,保证了幂等
    如果 tcc_fence_log 表中没有记录
    则插入一条记录,供后面重试时判断。
end note

tcc_fence_log <- RM: 插入防悬挂记录
note left
    执行 cancel 方法时
    判断 tcc_fence_log 是否存在当前 xid 的记录
    如果没有则向 tcc_fence_log 表插入一条记录
    状态是 STATUS_SUSPENDED,并且不再执行回滚操作
    后面执行 try 阶段方法时首先会向 tcc_fence_log 表插入一条当前 xid 的记
    这样就造成了主键冲突
end note

RM <- RM: 提交(commit)/回滚(cancel)

@enduml

优点

  • 一阶段完成直接提交事务,释放数据库资源,性能好
  • 相比AT模型,无需生成快照,无需使用全局锁,性能最强
  • 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库

缺点

  • 有代码侵入,需要人为编写try、Confirm和Cancel接口
  • 软状态,事务是最终一致

区别

XAATTCCSAGA
一致性
强一致
弱一致
弱一致
最终一致
隔离性
完全隔离
基于全局锁隔离
基于资源预留隔离
无隔离
代码侵入
有,要编写三个接口
有,要编写状态机和补偿业务 
性能
非常好
非常好
场景
对一致性、隔离性有高要求的业务
基于关系型数据库的大多数分布式事务场景
对性能要求较高的事务
有非关系型数据库要参与的事务
业务流程长、业务流程多 
参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口
Seata支持的三事务模式AT(TCC)、SAGAXA,它们之间的区别如下: 1. AT(TCC模式:AT模式是通过“尝试、确认、取消”三个步骤来实现分布式事务的。在AT模式中,Seata会为每个分布式事务创建一个全局事务,该全局事务包含多个本地事务。当一个本地事务提交时,Seata会将该提交操作视为“尝试”操作;当所有本地事务都提交时,Seata会将所有提交操作视为“确认”操作;当任意一个本地事务提交失败时,Seata会将所有提交操作视为“取消”操作,并回滚所有本地事务。 2. SAGA模式SAGA模式是通过“补偿”操作来实现分布式事务的。在SAGA模式中,Seata会为每个分布式事务创建一个全局事务,该全局事务也包含多个本地事务。当一个本地事务提交时,Seata会将该提交操作视为“正向”操作;当任意一个本地事务提交失败时,Seata会通过已经定义好的“补偿”操作来回滚相关的本地事务。 3. XA模式XA模式是通过全局事务管理器来实现分布式事务的。在XA模式中,Seata会为每个分布式事务创建一个全局事务,并通过JTA来实现全局事务的管理。当一个本地事务提交时,Seata会将该提交操作视为“参与”操作;当所有本地事务都参与时,Seata会将所有参与操作视为“提交”操作;当任意一个本地事务参与失败时,Seata会将所有参与操作视为“回滚”操作,并回滚所有本地事务。 总的来说,AT模式适用于对数据一致性要求较高的场景,SAGA模式适用于对数据一致性要求较低的场景,XA模式则是在使用JTA的情况下用于实现分布式事务的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值