在微服务架构中,一个业务操作往往需要调用多个不同服务的数据库,这就引入了跨服务的数据一致性问题,即分布式事务。Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。

一、Seata 概述

Seata 全称 Simple Extensible Autonomous Transaction Architecture,由阿里巴巴开源。它旨在解决微服务架构下的分布式事务问题,支持多种事务模式,能够确保全局数据一致性。

核心目标:对业务无侵入或低侵入,高性能,支持多种存储和事务模式。

二、Seata 核心概念

Seata 定义了三个核心角色:

  • TC (Transaction Coordinator) - 事务协调器:维护全局事务和分支事务的状态,驱动全局事务的提交或回滚。通常独立部署(Seata Server)。
  • TM (Transaction Manager) - 事务管理器:定义全局事务的边界,负责开启、提交或回滚一个全局事务。TM 向 TC 发起全局事务的开启、提交、回滚请求。
  • RM (Resource Manager) - 资源管理器:管理分支事务上的资源,向 TC 注册分支事务,汇报分支事务状态,驱动分支事务的提交或回滚。通常对应一个微服务实例,管理该服务本地数据库的操作。

事务模型

  • 全局事务:由 TM 开启的整个分布式事务,包含一个或多个分支事务。
  • 分支事务:每个 RM 本地执行的事务,是全局事务的组成部分。

三、Seata 整体架构

Seata 采用 TC 作为中心协调者,TM 和 RM 与 TC 通信。其基本工作流程如下:

  1. TM 向 TC 申请开启一个全局事务,TC 返回一个全局唯一的 XID。
  2. XID 在微服务调用链路上传播(通常通过拦截器植入 RPC 上下文)。
  3. 各个微服务的 RM 将本地事务注册到 TC 上,作为该全局事务的分支事务。
  4. TM 根据业务执行情况向 TC 发起全局提交或回滚。
  5. TC 驱动所有分支事务进行提交或回滚。

四、Seata 支持的事务模式详解

Seata 提供了四种事务模式:AT、TCC、Saga、XA。其中 AT 模式是其主推的、对业务无侵入的模式,其他模式用于特定场景。

1. AT 模式(Automatic Transaction)—— 自动补偿

AT 模式是 Seata 最具特色的模式,它基于本地 ACID 事务,通过两阶段提交(2PC)变种实现,但对业务代码几乎零侵入。

原理

  • 一阶段:业务数据和回滚日志在同一个本地事务中提交。在执行业务 SQL 之前,Seata 通过 JDBC 数据源代理拦截 SQL,解析 SQL 语义,生成“前镜像”(修改前的数据)和“后镜像”(修改后的数据),并将镜像数据组织成回滚日志记录(UNDO_LOG 表),与业务 SQL 一起提交。这一阶段直接提交了本地事务,释放了本地锁。
  • 二阶段
    • 如果全局事务成功,TC 通知分支事务删除 UNDO_LOG,异步完成,无需额外开销。
    • 如果全局事务失败,TC 通知分支事务回滚。RM 根据 UNDO_LOG 中的前镜像生成反向补偿 SQL,将数据恢复原样,然后删除 UNDO_LOG。

关键机制

  • 写隔离:AT 模式通过全局锁(由 TC 维护)保证不同全局事务对同一数据的写冲突。一阶段本地事务提交前,必须获取全局锁;获取失败则等待重试或回滚。全局锁在二阶段结束时释放(提交或回滚后)。
  • 读隔离:在数据库本地隔离级别基础上,AT 模式默认不保证全局读已提交,但可以通过 SELECT FOR UPDATE 语句触发全局锁检测,实现读已提交。

优点:对业务代码几乎无侵入,自动生成补偿 SQL,开发效率高。
缺点:需要建立 UNDO_LOG 表,对数据库有一定要求(支持本地事务),性能损耗较 TCC 略高(因生成前后镜像)。

2. TCC 模式(Try-Confirm-Cancel)—— 手动补偿

TCC 是一种业务层面的补偿型事务,需要业务方实现 Try、Confirm、Cancel 三个接口。

三个阶段

  • Try:完成业务检查,预留资源(例如,冻结库存、预扣余额)。
  • Confirm:真正执行业务,使用 Try 阶段预留的资源。Confirm 操作需保证幂等性。
  • Cancel:释放 Try 阶段预留的资源,同样需保证幂等性。

流程

  • TM 发起全局事务,调用各参与方的 Try 接口。
  • 如果所有 Try 成功,TM 调用各参与方的 Confirm 接口完成提交;否则调用 Cancel 接口进行回滚。

优点:性能较高(无需生成镜像,无全局锁),灵活性高,可自定义补偿逻辑。
缺点:对业务代码侵入性强,需自行实现幂等、空回滚、悬挂等复杂问题。

注意事项

  • 空回滚:当 Try 未执行,但 Cancel 被调用时(例如 RPC 超时,TM 判定失败直接 Cancel),Cancel 需能正确处理(识别事务状态,不做实际回滚)。
  • 幂等:Confirm 和 Cancel 可能被重复调用,必须保证幂等性。
  • 悬挂:指 Cancel 在 Try 之前执行,导致 Try 后续执行时资源被误释放。通常通过事务日志记录状态来避免。
3. Saga 模式

Saga 是一种长事务解决方案,将一个分布式事务拆分为一系列本地事务,每个本地事务都有对应的补偿操作。Saga 有两种实现方式:

  • 状态机引擎:Seata 提供了基于状态机的 Saga 实现,通过 JSON/XML 定义业务流程和补偿流程,由引擎驱动执行。
  • 命令协调:通过事件/命令的方式编排。

执行流程

  • 正常情况:按顺序执行每个本地事务,全部成功则事务结束。
  • 异常情况:如果某个本地事务失败,则按照相反顺序依次调用之前已成功事务的补偿操作。

优点:适合长事务,性能较好,可通过状态机可视化编排,适合业务流程复杂的场景。
缺点:缺乏隔离性(提交即可见,无法回滚已提交的中间状态),需要业务方自行处理隔离问题;补偿逻辑复杂。

4. XA 模式

XA 模式是基于 XA/Open DTP 标准的分布式事务协议,由数据库本身支持。

原理

  • 一阶段:TM 通知所有 RM 预提交,RM 执行 XA 准备,将事务信息持久化,但数据对其它事务不可见(处于锁定状态)。
  • 二阶段:如果所有 RM 预提交成功,TM 通知所有 RM 提交,否则通知回滚。

Seata 的 XA 模式:Seata 对 XA 做了封装,通过数据源代理自动管理 XA 事务,业务代码无需改动。

优点:对业务无侵入,强一致性,符合 ACID。
缺点:性能较差(资源锁定时间长,依赖于数据库的 XA 能力),不适合高并发场景。

五、AT 模式深度解析

因为 AT 模式是 Seata 的核心,我们深入理解其内部机制。

1. 全局锁

AT 模式为了保证写隔离,引入了全局锁机制。每个分支事务在提交本地事务前,必须向 TC 申请全局锁。全局锁的 key 通常由资源ID(库表)、行数据主键组成。TC 维护着全局锁的持有情况。如果全局锁已被其他全局事务持有,则当前事务必须等待或回滚。

全局锁的持有时间是从一阶段提交后到二阶段结束(提交或回滚)。这期间,该行数据对其它全局事务是“锁定”的,但对本地读(非全局事务)是可见的(取决于数据库隔离级别)。

2. 回滚日志(UNDO_LOG)

每个 RM 对应的数据库中需要建立 undo_log 表,用于存储一阶段生成的前后镜像。表结构包含分支事务ID、全局事务ID、前镜像、后镜像、回滚状态等字段。二阶段回滚时,Seata 会根据 undo_log 生成反向 SQL;提交时则删除日志。

3. 隔离级别
  • 读未提交:AT 模式默认情况下,一阶段提交后数据即对其他本地事务可见,如果二阶段回滚,则出现脏读。因此,AT 模式默认的全局隔离级别是读未提交。
  • 读已提交:如果需要全局读已提交,可以在业务查询中使用 SELECT FOR UPDATE,Seata 会通过代理拦截该语句,并尝试获取全局锁。如果该行被其他全局事务锁定且未提交,则当前查询会被阻塞,直到全局锁释放(即二阶段完成),从而避免了脏读。这相当于实现了读已提交隔离。
4. 性能考量

AT 模式的主要开销在于:SQL 解析、前后镜像生成、UNDO_LOG 写入、全局锁的申请与释放。相比直接本地事务,AT 模式会增加约 10%-30% 的性能损耗,但相比传统 2PC(如 XA)已经轻量很多。

六、Seata 部署与集成

1. Seata Server(TC)部署

Seata Server 支持多种存储模式(file、db、redis)和注册中心(nacos、eureka、consul、zk)。生产环境建议使用 db 模式存储事务日志,保证 TC 高可用。部署时需注意:

  • 使用 MySQL 存储事务会话信息,需要建表(global_table、branch_table、lock_table)。
  • 配置 registry.conf 指定注册中心和配置中心(如使用 Nacos)。
  • 启动 Seata Server:sh seata-server.sh
2. 客户端集成(以 Spring Boot 为例)
  • 引入依赖 spring-cloud-starter-alibaba-seata(Spring Cloud Alibaba 场景下)或 seata-spring-boot-starter
  • 配置 application.yml 中的 seata 部分:tx-service-group、服务分组、registry(与 TC 通信方式)。
  • 启用数据源代理:使用 @EnableAutoDataSourceProxy 或配置 Seata 数据源代理(自动配置已处理)。
  • 在事务发起方使用 @GlobalTransactional 注解标记全局事务边界。
  • 确保业务表所在的数据库有 undo_log 表(AT 模式)或业务方实现 TCC 接口。

七、实践中的注意事项

  1. 事务超时@GlobalTransactional 可设置超时时间,防止长时间占用全局锁。
  2. 幂等性设计:在 TCC 或 Saga 模式中,Confirm/Cancel 需支持幂等,通常通过事务状态表记录执行状态。
  3. 空回滚与悬挂(TCC):使用事务日志和防悬挂表来规避。例如在 Try 之前记录事务状态,Cancel 时检查是否 Try 过。
  4. 性能调优:AT 模式下,避免大事务(大量数据修改),减少全局锁持有时间;批量操作可考虑分拆多个小事务。
  5. 监控与告警:Seata 提供简单的监控页面,也可对接 Prometheus + Grafana。关注 TC 的吞吐量、失败事务数等指标。
  6. 混合模式使用:不同场景使用不同模式,如核心交易用 TCC,非核心用 AT。

八、与其他分布式事务方案的对比

方案优点缺点适用场景
Seata AT无侵入,自动补偿,性能较好需要 UNDO_LOG 表,全局锁可能引起冲突大多数微服务场景,特别是对开发效率要求高的团队
Seata TCC性能高,灵活控制资源侵入性强,需处理空回滚/悬挂高性能核心交易,资源预留场景
Seata Saga适合长流程,可视化编排隔离性需自行处理业务流程复杂,对一致性要求稍低的场景
Seata XA强一致,无侵入性能差,依赖数据库 XA对一致性要求极高、并发较低的遗留系统改造
LCN早期方案,简单锁粒度大,性能差,已不再维护不推荐新项目使用
HmilyTCC 实现,支持多种 RPC只支持 TCC,功能相对单一仅需 TCC 模式的轻量级场景
本地消息表可靠最终一致需维护消息表,开发量大对一致性要求不高,可接受延迟的场景

九、总结与选型建议

Seata 提供了丰富的分布式事务解决方案,覆盖了从强一致到最终一致的各种需求。在实际选型时,可以参考以下建议:

  • 优先考虑 AT 模式:对于大部分业务场景,如果对性能不是极端敏感,AT 模式可以极大降低开发成本,且基本能满足一致性和隔离性要求。
  • 核心资金链路用 TCC:对于涉及资金、库存等核心资源,需要精细控制资源预留和释放的场景,TCC 能提供更好的性能和灵活性。
  • 长流程业务用 Saga:对于业务流程复杂、涉及多个服务且耗时较长的场景,Saga 状态机可以清晰定义补偿逻辑,避免长时间锁定资源。
  • 严格强一致用 XA:只有在对一致性要求极为严格(如金融对账),且并发量不高,同时数据库支持 XA 时,才考虑 XA 模式。

Seata 仍在快速发展中,社区活跃,建议关注其最新版本特性,如对多注册中心的支持、性能优化等。合理使用 Seata,能有效解决微服务架构下的分布式事务难题。

更多推荐