1273 字
3 分钟
Saga 模式:长事务的编排方案
某旅行平台预订流程:用户需要同时预订机票、酒店和租车。三个服务分别调用,如果机票预订成功但酒店满房,需要取消机票并通知用户。整个过程可能持续数秒甚至数分钟,2PC 的长时间锁阻塞不可接受,TCC 的资源冻结在跨企业场景下也不现实。Saga 模式通过正向操作与补偿操作配对,成为长事务场景的最佳选择。
一、Saga 的核心思想
Saga 将长事务拆分为多个本地事务,每个本地事务都有对应的补偿操作:
- 正向操作:执行业务逻辑
- 补偿操作:撤销正向操作的影响
如果某个步骤失败,按反向顺序依次执行已完成步骤的补偿操作。
正向流程:T1 → T2 → T3 → T4(成功)失败回滚:T1 → T2 → T3 失败 → C3 → C2 → C1(补偿)Info
Saga 的补偿操作不是”回滚”,而是”语义上的撤销”。例如,扣款的补偿不是恢复余额,而是增加一笔等额的退款记录。两者的业务含义不同。
二、两种编排方式
2.1 编排式(Orchestration)
由一个中央协调器(Orchestrator)统一控制流程:
sequenceDiagram
participant O as 协调器
participant F as 机票服务
participant H as 酒店服务
participant C as 租车服务
O->>F: 预订机票
F-->>O: 成功
O->>H: 预订酒店
H-->>O: 失败
O->>F: 取消机票(补偿)
优点:
- 流程集中管理,逻辑清晰
- 容易监控和调试
- 适合复杂流程
缺点:
- 协调器是单点,需要高可用保障
- 协调器与所有服务耦合
2.2 协调式(Choreography)
各服务通过事件驱动,自主决定下一步操作:
sequenceDiagram
participant F as 机票服务
participant H as 酒店服务
participant C as 租车服务
participant E as 事件总线
F->>E: 机票预订成功事件
E->>H: 触发酒店预订
H->>E: 酒店预订失败事件
E->>F: 触发机票取消
优点:
- 去中心化,无单点故障
- 服务间松耦合
- 适合简单流程
缺点:
- 流程分散,难以整体理解
- 调试困难,需要分布式追踪
- 循环依赖风险
2.3 两种方式对比
| 维度 | 编排式 | 协调式 |
|---|---|---|
| 流程可见性 | 高 | 低 |
| 单点风险 | 有 | 无 |
| 耦合度 | 中 | 低 |
| 调试难度 | 低 | 高 |
| 适用场景 | 复杂流程 | 简单流程 |
三、补偿操作设计
3.1 补偿的语义
补偿操作不是物理回滚,而是语义上的撤销:
| 正向操作 | 补偿操作 | 说明 |
|---|---|---|
| 扣款 100 元 | 退款 100 元 | 不是恢复余额,而是新增退款记录 |
| 创建订单 | 取消订单 | 订单状态变为”已取消”,而非删除 |
| 扣减库存 | 恢复库存 | 增加可用库存 |
| 发送邮件 | 发送通知邮件 | 无法撤回已发邮件,发送补充说明 |
3.2 补偿的幂等性
补偿操作可能被重复调用,必须保证幂等:
public void cancelOrder(String txnId, String orderId) { // 幂等性检查 if (compensationLog.exists(txnId, "CANCEL_ORDER")) { return; // 已补偿,直接返回 }
Order order = orderMapper.selectById(orderId); if (order.getStatus() == OrderStatus.CANCELLED) { return; // 已取消,直接返回 }
order.setStatus(OrderStatus.CANCELLED); orderMapper.updateById(order);
compensationLog.record(txnId, "CANCEL_ORDER");}3.3 补偿的顺序
补偿必须按正向操作的反序执行:
正向:T1 → T2 → T3补偿:C3 → C2 → C1如果 T3 失败,先补偿 T2,再补偿 T1。这是因为后续操作可能依赖前序操作的结果。
四、Saga 的隔离性问题
Saga 不提供全局隔离性,可能出现以下问题:
4.1 脏读
事务 T1 执行后,T2 读取了 T1 的中间结果,但 T1 最终被补偿。
T1: 扣减库存(库存从 10 变为 9)T2: 其他事务读取库存为 9T1 补偿: 恢复库存(库存从 9 变为 10)T2 基于过期数据做了决策4.2 不可重复读
同一事务内两次读取同一数据,结果不同。
4.3 幻读
其他事务在 Saga 执行期间插入了新数据。
4.4 隔离性保障策略
| 策略 | 原理 | 代价 |
|---|---|---|
| 语义锁 | 在业务数据上标记”处理中”状态 | 增加业务复杂度 |
| 交换律 | 设计可交换的操作 | 限制业务模型 |
| 悲观视图 | 重排 Saga 步骤避免脏读 | 可能增加延迟 |
| 版本控制 | 使用乐观锁检测冲突 | 冲突时需重试 |
五、Seata Saga 实践
Seata 提供了基于状态机的 Saga 实现。
5.1 状态机定义
{ "Name": "travelBooking", "Comment": "旅行预订 Saga", "StartState": "BookFlight", "States": { "BookFlight": { "Type": "ServiceTask", "ServiceName": "flightService", "ServiceMethod": "book", "CompensateState": "CancelFlight", "Next": "BookHotel", "Input": ["$.flightInfo"], "Output": {"flightBookingId": "$.bookingId"} }, "BookHotel": { "Type": "ServiceTask", "ServiceName": "hotelService", "ServiceMethod": "book", "CompensateState": "CancelHotel", "Next": "BookCar", "Input": ["$.hotelInfo"], "Output": {"hotelBookingId": "$.bookingId"} }, "BookCar": { "Type": "ServiceTask", "ServiceName": "carService", "ServiceMethod": "book", "CompensateState": "CancelCar", "Next": "Succeed", "Input": ["$.carInfo"] }, "CancelFlight": { "Type": "CompensateSubMachine", "ServiceName": "flightService", "ServiceMethod": "cancel" }, "CancelHotel": { "Type": "CompensateSubMachine", "ServiceName": "hotelService", "ServiceMethod": "cancel" }, "CancelCar": { "Type": "CompensateSubMachine", "ServiceName": "carService", "ServiceMethod": "cancel" }, "Succeed": { "Type": "Succeed" } }}5.2 状态机执行
// 启动 Saga 状态机StateMachineEngine engine = new DbStateMachineEngine(dataSource);StateMachineInstance instance = engine.start( "travelBooking", BusinessType.COMMON, params);
// 查询执行状态StateMachineInstance status = engine.queryInstance(instance.getId());六、Saga 适用场景
6.1 适合使用 Saga 的场景
- 长事务(秒级到分钟级)
- 跨企业/跨组织的业务流程
- 参与者数量较多
- 可以接受最终一致性
- 补偿操作语义明确
6.2 不适合使用 Saga 的场景
- 对隔离性要求高(如金融核心交易)
- 补偿操作难以定义(如发送邮件)
- 参与者数量少且事务短(2PC 更简单)
- 实时性要求极高
七、Saga 与其他方案的对比
| 维度 | 2PC | TCC | Saga |
|---|---|---|---|
| 一致性 | 强一致 | 最终一致 | 最终一致 |
| 隔离性 | 强 | 中 | 弱 |
| 阻塞 | 严重 | 无 | 无 |
| 事务时长 | 短 | 中 | 长 |
| 业务侵入 | 无 | 高 | 中 |
| 补偿设计 | 不需要 | 需要 | 需要 |
| 适用场景 | 短事务 | 高并发 | 长流程 |
Saga 模式通过正向操作与补偿操作配对,解决了长事务场景下的分布式一致性问题。虽然不提供全局隔离性,但在跨服务、跨企业的业务流程中,Saga 是最实用的分布式事务方案。选择编排式还是协调式,取决于业务流程的复杂度和团队的技术能力。
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
Saga 模式:长事务的编排方案
https://blog.souloss.com/posts/distributed/distributed-saga-pattern/ 部分信息可能已经过时
相关文章 智能推荐
1
TCC 模式:业务层面的分布式事务方案
分布式系统深入 深入解析 TCC 模式——Try/Confirm/Cancel 三阶段流程、空回滚与悬挂问题、幂等性设计与 Seata 实践
2
2PC 与 3PC:分布式事务的协议基础
分布式系统深入 深入解析两阶段提交与三阶段提交协议——原理、阻塞问题与工程实践中的改进方案
3
API 网关:微服务的统一入口
分布式系统深入 深入解析 API 网关——限流算法、熔断器模式、灰度发布与服务发现集成的工程实践
4
服务发现:微服务通信的基础设施
分布式系统深入 深入理解服务发现机制——从 DNS 到注册中心,客户端发现与服务端发现的差异与工程实践
5
Istio:服务网格的工程实践
分布式系统深入 深入解析 Istio 服务网格——Sidecar 代理、流量管理、安全策略与可观测性的工程实践






