SEATA AT vs SAGA vs 本地消息表

AT模式

是一种无侵入的解决方案,基于SQL解析自动生成回滚日志。它的优点是对业务代码侵入小,只需要添加@GlobalTransactional注解即可。适合短事务场景(1秒左右内处理完事务),比如订单支付、库存扣减等。但缺点是仅支持关系型数据库,在长事务场景下会有全局锁竞争问题。

SEATA 的 AT 模式(Automatic Transaction) 是一种基于改进的两阶段提交(2PC)协议的无侵入分布式事务解决方案,通过自动生成数据快照和回滚日志,实现分布式事务的最终一致性。以下是其核心原理及阶段划分:


一、AT 模式核心原理

  1. 无侵入设计
    业务代码无需改造,仅需通过 @GlobalTransactional 注解标记全局事务边界。
  2. 两阶段提交优化
    与传统 XA 模式不同,AT 模式在一阶段直接提交本地事务,释放数据库资源,通过全局锁undo_log 表保障隔离性和可回滚性。
  3. 关键组件
    • TC(事务协调器):独立部署,管理全局事务状态和分支协调。
    • TM(事务管理器):定义全局事务边界(如注解触发)。
    • RM(资源管理器):拦截 SQL、生成回滚日志,并与 TC 通信。

二、一阶段:本地事务提交与准备

目标:执行业务 SQL,记录数据快照,注册分支事务。
流程

  1. SQL 解析与拦截
    RM 通过数据源代理拦截业务 SQL,解析类型(INSERT/UPDATE/DELETE)、表名、条件等。
  2. 生成前镜像(Before Image)
    执行 SQL 前,查询并保存修改前的数据快照(例如 SELECT * FROM table WHERE id=1)。
  3. 执行业务 SQL
    提交 SQL 操作(如 UPDATE table SET stock=90 WHERE id=1)。
  4. 生成后镜像(After Image)
    执行 SQL 后,再次查询数据,保存修改后的状态。
  5. 记录回滚日志(undo_log)
    将前后镜像组成 JSON 格式的 undo_log,插入业务数据库的 undo_log 表中。
  6. 注册分支事务与全局锁
    • 向 TC 注册分支事务,申请目标数据的全局锁(例如锁定 id=1 的记录)。
    • 同一个本地事务中提交业务数据和 undo_log,释放本地数据库锁(非全局锁)。

关键点:一阶段已完成本地事务提交,释放连接资源,性能较高;全局锁防止其他事务修改同一数据。


三、二阶段:全局提交或回滚

目标:根据 TC 的决策,异步清理或回滚数据。
流程

  1. TC 决策
    TM 通知 TC 全局事务结束,TC 检查所有分支事务状态。
  2. 全局提交(所有分支成功)
    • TC 通知各分支异步删除 undo_log 记录。
    • 无需数据操作(因一阶段已提交),仅清理日志,效率极高。
  3. 全局回滚(任一分支失败)
    • TC 通知成功分支根据 undo_log 回滚。
    • 回滚步骤
      • 校验脏写:比较当前数据与后镜像是否一致。若不一致,说明数据被其他事务修改,需人工介入。
      • 生成反向 SQL:根据前镜像生成逆向操作(如将 stock=90 回滚为 stock=100)。
      • 执行回滚:在本地事务中执行反向 SQL,并删除 undo_log

⚠️ 脏写校验:回滚前校验数据一致性,避免覆盖其他事务的修改。


四、关键机制与注意事项

  1. 隔离性保障
    • 写隔离:通过全局锁(SELECT FOR UPDATE)确保同一记录仅一个全局事务可修改。
    • 读隔离:默认读未提交(Read Uncommitted),可通过 SELECT FOR UPDATE 升级为读已提交(Read Committed)。
  2. 性能优化
    • 一阶段提交释放本地资源,二阶段异步清理,减少锁竞争。
    • 避免长事务,防止全局锁长时间占用。
  3. 适用场景
    • 适合:Java 技术栈、短事务(如订单创建、库存扣减)。
    • 不适合:跨语言微服务、非关系型数据库、金融级强一致性场景(需 TCC 模式)。

SAGA模式

是为长事务(数秒)设计的解决方案,通过正向操作和补偿操作来实现最终一致性。它的优点是没有全局锁,适合跨多个服务的业务流程,参与者可以异步执行。但缺点是需要手动实现补偿逻辑,状态管理复杂。
由于 Saga 事务不保证隔离性, 在极端情况下可能由于脏写无法完成回滚操作, 比如举一个极端的例子, 分布式事务内先给用户A充值, 然后给用户B扣减余额, 如果在给A用户充值成功, 在事务提交以前, A用户把余额消费掉了, 如果事务发生回滚, 这时则没有办法进行补偿了。这就是缺乏隔离性造成的典型的问题, 实践中一般的应对方法是:
业务流程设计时遵循“宁可长款, 不可短款”的原则, 长款意思是客户少了钱机构多了钱, 以机构信誉可以给客户退款, 反之则是短款, 少的钱可能追不回来了。所以在业务流程设计上一定是先扣款。
有些业务场景可以允许让业务最终成功, 在回滚不了的情况下可以继续重试完成后面的流程, 所以状态机引擎除了提供“回滚”能力还需要提供“向前”恢复上下文继续执行的能力, 让业务最终执行成功, 达到最终一致性的目的。

在 Seata 分布式事务框架中,SAGA 模式AT 模式是两种主流解决方案,但其设计目标和适用场景存在显著差异。以下是结合核心原理、适用性及实践建议的选型指南:

Saga的其他替代方案:本地消息表

⚙️ 一、核心机制对比

维度 AT 模式 SAGA 模式
一致性级别 最终一致(默认) 最终一致
事务锁机制 依赖全局锁(高并发下可能阻塞) 无全局锁(异步执行,无阻塞)
业务侵入性 无侵入(仅需注解) 需手动实现补偿逻辑
事务时长支持 短事务(秒级) 长事务(分钟/小时级)
隔离性 弱隔离(需 @GlobalLock 防脏读) 无隔离(可能脏读)

🎯 二、适用场景决策

优先选择 AT 模式

  1. 简单跨服务事务
    • 例如:订单创建(操作订单表)→ 库存扣减(操作库存表),事务链路短且逻辑简单。
    • 优势:无需额外编码,通过 @GlobalTransactional 自动管理回滚。
  2. 强依赖关系型数据库
    • 仅支持 MySQL/Oracle 等 ACID 数据库,无法接入 Redis/MongoDB 等 NoSQL。
  3. 对开发效率要求高
    • 快速上线场景,避免补偿逻辑开发成本。

优先选择 SAGA 模式

  1. 长流程业务
    • 例如:电商下单(订单→支付→物流→通知),涉及多服务且执行时间长(>30秒)。
    • 优势:无锁设计避免资源长期占用,支持异步执行。
  2. 跨异构系统集成
    • 需调用外部服务(如第三方支付、海关清关),无法改造其接口实现 TCC 时。
  3. 高并发且容忍最终一致
    • 如秒杀活动中库存扣减与订单创建的分离,通过补偿保证最终一致。

⚠️ 三、关键缺陷与规避方案

模式 典型问题 解决方案
AT 模式 高并发下全局锁竞争 分库分表降低锁粒度;设置合理超时时间
复杂 SQL 解析失败(如子查询) 手动编写补偿 SQL 或改用 TCC
SAGA 模式 补偿逻辑实现复杂 用状态机引擎(如 Seata StateMachine)标准化流程
补偿失败导致数据不一致 增加重试机制 + 人工兜底干预

💡 五、实践建议

  1. 混合模式使用
    复杂系统中可组合模式(如核心支付用 TCC,物流通知用 SAGA)。
  2. SAGA 补偿设计原则
    • 补偿操作需幂等(通过业务 ID 去重)。
    • 正向操作与补偿操作成对设计(如 createOrdercancelOrder)。
  3. 监控与治理
    • AT 模式监控全局锁竞争率;SAGA 模式跟踪事务状态机执行链路。

💎 总结

  • 选 AT:短事务、简单逻辑、追求开发效率、强依赖关系型数据库。
  • 选 SAGA:长事务、跨异构系统、高并发无锁需求、业务容忍最终一致。
    实际选型需结合事务时长一致性要求团队技术储备综合判断,必要时可混合模式灵活应对。

参考资料

posted @ 2025-08-12 15:19  向着朝阳  阅读(72)  评论(0)    收藏  举报