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),负责向各服务发送指令并处理补偿逻辑。流程可控,适合复杂业务。
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): 事务执行时间从秒级到分钟级,不适合持有数据库锁。
- 高可用要求: 允许部分失败,通过补偿恢复,不阻塞整个系统。
- 最终一致性可接受: 业务允许短暂的数据不一致窗口(如电商订单状态同步)。
- 已有本地事务支持: 每个微服务已有成熟的本地事务机制,只需增加补偿逻辑。
1.4 补偿事务设计要点
补偿事务是Saga的核心保障机制,设计时需遵循以下原则:
- 幂等性: 补偿操作可重复执行,多次执行结果与一次相同。
- 可交换性: 补偿与正向事务在语义上可交换,不依赖执行顺序。
- 空补偿安全: 若正向事务未执行,补偿操作应无副作用。
- 资源释放: 补偿必须释放正向事务占用的所有资源(如库存、额度)。
实践建议: 在微服务中为每个写操作预留事务ID字段,补偿时通过事务ID定位原始记录,避免重复补偿或误补偿。
1.5 本章小结
- Saga通过本地事务+补偿事务实现分布式最终一致性。
- 与ACID相比,Saga牺牲了全局隔离性,换取了高可用和长事务支持。
- 适用场景包括跨服务业务流程、长活事务、高可用系统;不适用于强一致性或补偿不可实现的场景。
- 补偿事务设计需保证幂等性和空补偿安全。