跳到主要内容
约 4 分钟2 张卡

Saga

Saga 用一系列本地事务推进跨服务流程。后续步骤失败时,补偿事务修正业务结果。本文负责补偿、中间状态、隔离和恢复方向。

1. 面试核心​

先记住这几条,再读正文
  • 本地提交与可见性。 Saga 的每个本地事务独立提交,中间结果可被其他请求读取。
  • 业务补偿。 补偿是新的业务事务,退款与释放预留用于修正结果。卡 · 本地事务步骤
  • 编排与协同。 编排式由协调器推进,协同式由服务通过事件推进。
  • 并发隔离。 Saga 缺少跨步骤隔离,预留与版本条件可限制并发冲突。卡 · 并发补偿与旧快照
  • 不可逆步骤后的恢复。 pivot 是流程的不可逆转折步骤。它成功后,后续步骤按设计重试并向前恢复到完成状态。

2. 本地事务步骤​

订单流程可拆成创建订单、预留库存、授权支付和履约。每一步保存本地结果,再触发下一步。

API 应暴露 PENDING_PAYMENT 等中间状态。用户能查询进度,重试沿用原业务 ID。最终成功需要满足流程定义的全部条件。

3. 补偿​

库存预留可通过释放预留补偿。支付授权可撤销,正式扣款则需退款。退款具有独立流水,也会产生到账延迟或手续费。

补偿修正业务效果,并保留操作历史。已发邮件、已读通知和物理发货需更正或人工处置。补偿顺序由业务依赖决定。

4. 编排式 Saga​

协调器记录步骤,并根据结果发出后续命令。分支、重试和超时集中管理,适合复杂流程。

状态与待发送命令需持久化。协调器重启后按记录继续推进。业务数据仍由参与者维护,协调器拥有流程状态。

5. 协同式 Saga​

协同式让服务订阅事件并发布后续结果。简单流程可以省去集中编排器。

步骤增多后,事件依赖更难追踪。系统仍需稳定 Saga ID 和可查询的流程投影。循环触发与重复事件应纳入测试。

6. 补偿的幂等与重试​

参与者按 Saga ID 和步骤 ID 保存补偿结果。重复调用沿用同一标识。状态与本地资源变化共同提交。

暂时失败可退避重试。持续失败进入明确待处理状态,并限制继续扩大风险。对账和人工恢复见分布式流程恢复。

7. 并发隔离​

Saga 的本地事务彼此分离。其他流程会在两步之间读写同一资源。语义锁、预留、版本检查和按业务键串行可限制冲突。

7.1 并发补偿与旧快照​

假设可用库存为 10。流程 A 预留 2 件后,库存为 8。流程 B 再预留 3 件后,库存为 5。

A 失败后若把库存写回旧值 10,就抹掉了 B 的预留。正确补偿只释放 A 的 2 件,结果应为 7。释放以 A 的预留 ID 去重。

预留记录从 RESERVED 转为 RELEASED。状态转换与加回库存放在同一事务中。重复补偿读取已有终态,避免再次加库存。

8. 不可逆步骤​

pivot 是流程恢复方向发生变化的边界。成功前可执行业务补偿,成功后后续步骤需向前恢复。

发货等不可逆动作应放在必要检查与预留之后。pivot 后的步骤应可重试,并按设计最终完成。若业务仍会永久拒绝,应重新设计边界或准备人工履约。

9. 超时与未知结果​

调用超时只说明未收到结果。协调器可查询原业务 ID,等待结果事件,或进入 UNKNOWN 状态核对。

补偿也要与迟到的正向操作协调。参与者状态机需拒绝相互冲突的终态。支持提前登记取消意图时,可据此挡住迟到操作。

10. 常见问题​

10.1 Saga 的一致性范围​

Saga 通过重试和补偿达到合法终态。中间结果可见,跨步骤隔离需要业务设计。同步强不变量应由本地约束或预留先保护。

10.2 补偿失败与人工状态​

11 · 面试题卡片​

11.1 Saga 的补偿为什么不等于数据库回滚​

出现公司:阿里巴巴

考察重点

  • 已提交本地事务和可见中间状态。
  • 业务补偿、不可逆动作与并发隔离。
  • 编排、协同、超时未知和人工处置。

相关内容:本地事务步骤至超时与未知结果。

参考回答

Saga 补偿执行的是新的业务事务。

原步骤已经提交,其他请求也可读到结果。退款或释放预留修正业务效果,但保留历史和外部影响。

补偿需幂等,并避免覆盖其他流程的新状态。调用超时先核对原结果。不可逆边界后的步骤向前恢复。持续失败进入可告警的待处理状态,修复后再结束流程。

11.2 Saga 补偿库存时,为什么不能直接写回操作前的库存值?​

出现公司:暂无已核验的公开来源(本站自测)

考察重点:并发更新、预留标识与条件补偿。

相关内容:并发补偿与旧快照。

参考回答

旧快照会覆盖其他流程的合法预留。

库存 10 件,A 预留 2 件,B 再预留 3 件。A 失败后只释放自己的 2 件,结果应为 7。释放记录与库存修改共同提交,并按预留 ID 去重。

12. 参考资料​