基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

Seata AT 模式的工作原理

知识点图片

Seata 的 AT (Automatic Transaction) 模式 是 Seata 默认且最常用的分布式事务模式。它的核心思想是“两阶段提交协议(2PC)的演进”,最大的特点是对业务无侵入(业务代码无需为了分布式事务编写补偿逻辑),通过代理数据源自动完成事务的协调。

下面为您详细拆解 Seata AT 模式的工作原理。


一、 核心组件与前提条件

在理解原理之前,先回顾 Seata 的三大核心组件:

  1. TC (Transaction Coordinator) - 事务协调者: 独立的 Seata 服务端,维护全局和分支事务的状态,驱动全局事务提交或回滚。
  2. TM (Transaction Manager) - 事务管理器: 嵌入在业务应用中,负责开启全局事务,并最终发起全局提交或全局回滚的决议。
  3. RM (Resource Manager) - 资源管理器: 嵌入在业务应用中,负责管理本地数据库资源,与 TC 交涉注册分支事务和报告状态,并接收 TC 的指令执行第二阶段。

AT 模式的前提条件:

  • 必须是支持本地 ACID 事务的关系型数据库(如 MySQL、Oracle 等)。
  • 业务应用必须使用 Seata 的 JDBC 数据源代理(DataSourceProxy)。
  • 每个业务数据库中必须创建一张特定结构的表:undo_log(回滚日志表)。

二、 AT 模式的两阶段工作流程

AT 模式将分布式事务分为两个阶段:执行阶段(Phase 1)决议阶段(Phase 2)

第一阶段(Phase 1):执行并提交本地事务

在这一阶段,Seata 会拦截并解析业务 SQL,记录数据修改前后的状态,并与业务 SQL 在同一个本地事务中提交。这样可以快速释放数据库的本地锁。

具体步骤:

  1. 解析 SQL: Seata 的数据源代理拦截到业务 SQL(例如 UPDATE user SET balance = balance - 100 WHERE id = 1),解析出表名、条件、修改的字段等。
  2. 查询前置镜像(Before Image): 在执行 SQL 前,Seata 根据解析出的条件,查出修改前的数据状态。
  3. 执行业务 SQL: 执行真正的业务更新操作。
  4. 查询后置镜像(After Image): 在执行 SQL 后,再次查询该行数据,获取修改后的数据状态。
  5. 生成回滚日志: 将 Before Image 和 After Image 以及业务 SQL 信息组装成一条回滚日志(Undo Log)。
  6. 申请全局锁: (关键步骤) 在本地事务提交前,RM 会向 TC 申请该记录的全局锁(由 表名 + 主键 组成)。如果拿不到全局锁,本地事务将不断重试,直到超时失败回滚。
  7. 本地事务提交:业务数据的修改回滚日志(Undo Log 的插入) 在同一个本地数据库事务中提交。
  8. 汇报状态: 本地事务提交成功后,RM 向 TC 汇报分支事务执行成功。

阶段一总结: 业务数据和回滚日志被一起提交到数据库,本地锁已被释放,极大地提高了并发性能。

第二阶段(Phase 2):全局决议(提交或回滚)

当 TM 所在的微服务执行完所有业务逻辑后,会根据是否有异常发生,向 TC 发起全局提交或全局回滚的请求。TC 收到请求后,会通知所有相关的 RM 执行第二阶段。

情况 A:全局提交(Global Commit)
如果整个微服务调用链路都没有报错:

  1. TC 通知各个 RM 提交分支事务。
  2. RM 收到提交指令后,由于第一阶段业务数据已经提交到了数据库,所以第二阶段只需清理 undo_log 表中的对应记录即可。
  3. 这个清理过程是放入内存队列中异步批量执行的,非常快,对业务几乎无影响

情况 B:全局回滚(Global Rollback)
如果链路中某个微服务报错,TM 发起全局回滚:

  1. TC 通知各个 RM 回滚分支事务。
  2. RM 收到回滚指令后,通过分支事务 ID 找到对应的 undo_log 记录。
  3. 数据校验(脏写校验): RM 取出 undo_log 中的 After Image(即自己第一阶段修改后的值),与当前数据库里的实际值进行比对。
    • 如果一致,说明没有被其他事务篡改过,允许回滚。
    • 如果不一致,说明发生了“脏写”(有非 Seata 事务直接改了数据库),此时会触发异常报警,需要人工介入处理。
  4. 还原数据: 校验通过后,根据 Before Image 生成反向 SQL(例如把 UPDATE 改回原来的值),并执行。
  5. 清理日志: 删除该条 undo_log 记录。
  6. 提交本地回滚事务: 将反向 SQL 和清理日志操作在一个本地事务中提交。
  7. RM 向 TC 报告分支回滚完成。同时释放 TC 端的全局锁。

三、 隔离性保障 (Isolation)

在分布式环境下,多个事务并发修改同一条数据会带来隔离性问题。Seata AT 模式是如何解决的?

1. 写隔离 (Write Isolation)

Seata 通过 全局锁(Global Lock) 来保证写隔离。

  • 全局锁的获取: 阶段一本地事务提交前,必须获取 TC 的全局锁。
  • 阻止脏写: 只要全局事务还没结束(未进行 Phase 2),TC 里的全局锁就不会释放。其他 Seata 事务如果想修改同一行数据,在阶段一提交前会发现全局锁被占用,从而等待。
  • 防非 Seata 事务脏写: 如果是普通的 JDBC 事务绕过 Seata 直接改数据库,Seata 怎么防?这就是前面提到的 Phase 2 回滚时的 After Image 校验机制,发现被改了就会拦截回滚并报警。

2. 读隔离 (Read Isolation)

  • 默认隔离级别: AT 模式默认的全局隔离级别是 读未提交(Read Uncommitted)。因为阶段一本地事务已经提交了,其他本地事务是可以查到修改后的数据的。
  • 如何实现“读已提交(Read Committed)”? 如果业务对一致性要求很高,不能读到中间状态,可以使用 SELECT ... FOR UPDATE 语句。Seata 的代理层会拦截这个语句,在查询前要求先获取 全局锁。如果全局锁被其他未完成的分布式事务占着,这个查询就会阻塞等待,从而实现了全局的读已提交。

四、 AT 模式的优缺点

优点:

  1. 零代码侵入: 开发者只需要使用 @GlobalTransactional 注解,写正常的 JDBC 代码即可,不需要像 TCC 模式那样自己去写 Try/Confirm/Cancel 三个方法。
  2. 性能较高: 相比于传统的 XA 强一致性事务,AT 模式在第一阶段就把本地数据库锁释放了,极大缩短了数据库锁的持有时间,提高了并发吞吐量。

缺点:

  1. 特定数据库依赖: 依赖关系型数据库的 ACID 特性,且 Seata 需要实现对应数据库方言的 SQL 解析器(目前支持 MySQL、Oracle、PostgreSQL 等主流 RDBMS)。
  2. 全局锁竞争: 如果业务存在极度集中的“热点数据”更新(如扣减同一个热门商品的库存),多个分布式事务争抢同一个行记录的全局锁会导致性能瓶颈。
  3. 最终一致性: 它不是像 XA 那样的强一致性,在 Phase 1 之后、Phase 2 之前,存在短暂的数据不一致窗口期(本地数据已改,但全局事务未结束)。

总结

Seata AT 模式本质上是一个基于代理数据源、通过记录回滚日志来实现自动补偿的、非侵入式的两阶段提交架构。它巧妙地平衡了分布式事务的易用性和性能,是微服务架构中最常采用的分布式事务落地方案。

00:00
00:00