1. Saga事务基础:Saga模式定义、Saga与ACID对比、Saga适用场景

1.1 Saga模式定义

Saga是一种用于管理长活事务的分布式事务模式,由Hector Garcia-Molina和Kenneth Salem于1987年提出。它将一个全局事务拆分为多个本地事务(Local Transaction),每个本地事务都有对应的补偿事务(Compensation Transaction)。当某个本地事务失败时,Saga会依次执行之前已成功事务的补偿操作,从而回滚整个业务流程。

核心思想: 放弃ACID的原子性与隔离性,通过补偿机制实现最终一致性。

Saga的两种协调模式:

  • 编排模式(Choreography): 每个服务在完成本地事务后,发布事件触发下一个服务。无中心协调器,耦合度低,但流程追踪困难。
  • 协调器模式(Orchestration): 引入一个中心化的Saga协调器(Orchestrator),负责向各服务发送指令并处理补偿逻辑。流程可控,适合复杂业务。
Saga 两种协调模式对比 编排模式(Choreography) 服务A 服务B 服务C 服务D 事件驱动,无中心协调器 耦合度低,但追踪困难 协调器模式(Orchestration) Saga协调器 服务A 服务B 服务C 中心化协调器控制流程 流程可控,适合复杂业务 提示:OpenTelemetry 在编排模式中通过事件上下文传播追踪,在协调器模式中通过协调器 Span 串联全局事务。

1.2 Saga与ACID对比

传统ACID事务适用于单体数据库内的短事务,而Saga面向分布式微服务场景,在原子性和隔离性上做出了妥协,以换取更高的可用性和吞吐量。

特性 ACID事务 Saga事务
原子性 全有或全无,通过Undo日志回滚 通过补偿事务实现最终一致性
一致性 事务前后数据完整约束 最终一致性,允许中间状态
隔离性 严格隔离(如可串行化) 无全局隔离,需应用层处理脏读
持久性 提交即持久 依赖本地事务持久化,补偿也持久
适用范围 单体数据库、短事务 微服务、跨服务长事务
锁机制 行锁/表锁,阻塞等待 无全局锁,乐观重试
典型实现 MySQL InnoDB、PostgreSQL Seata、Axon、Eventuate
关键差异: Saga 不提供全局隔离性。在 Saga 执行过程中,其他服务可能读到未完成事务的中间数据。开发者必须通过语义锁或幂等性设计来避免数据不一致。

1.3 Saga适用场景

Saga并非万能方案,以下场景最适合引入Saga事务:

  • 跨微服务的业务流程: 如订单创建涉及库存扣减、支付扣款、积分增加等多个独立服务。
  • 长活事务(Long-Lived Transaction): 事务执行时间从秒级到分钟级,不适合持有数据库锁。
  • 高可用要求: 允许部分失败,通过补偿恢复,不阻塞整个系统。
  • 最终一致性可接受: 业务允许短暂的数据不一致窗口(如电商订单状态同步)。
  • 已有本地事务支持: 每个微服务已有成熟的本地事务机制,只需增加补偿逻辑。
Saga 适用场景 vs 不适用场景 ✅ 适用场景 跨微服务业务流程(订单→库存→支付) 长活事务(秒级~分钟级) 高可用、允许最终一致性 已有本地事务,需增加补偿逻辑 ❌ 不适用场景 强一致性要求(如银行转账) 短事务且单库可完成 补偿逻辑不可实现或成本过高 业务不允许任何中间状态

1.4 补偿事务设计要点

补偿事务是Saga的核心保障机制,设计时需遵循以下原则:

  1. 幂等性: 补偿操作可重复执行,多次执行结果与一次相同。
  2. 可交换性: 补偿与正向事务在语义上可交换,不依赖执行顺序。
  3. 空补偿安全: 若正向事务未执行,补偿操作应无副作用。
  4. 资源释放: 补偿必须释放正向事务占用的所有资源(如库存、额度)。
实践建议: 在微服务中为每个写操作预留事务ID字段,补偿时通过事务ID定位原始记录,避免重复补偿或误补偿。

1.5 本章小结

  • Saga通过本地事务+补偿事务实现分布式最终一致性。
  • 与ACID相比,Saga牺牲了全局隔离性,换取了高可用和长事务支持。
  • 适用场景包括跨服务业务流程、长活事务、高可用系统;不适用于强一致性或补偿不可实现的场景。
  • 补偿事务设计需保证幂等性和空补偿安全。