SuperAPI AI 工具集

arch-saga

编程与开发

查看项目

更新于 10-16 16:26

技能介绍

用途

当业务事务跨越多个服务或多个聚合,并且它们无法共享单个事务时,使用此技能。适用于以下情况:

  • 一个业务流程横跨多个服务或多个聚合,且无法共享一个事务。
  • 某些步骤是外部的(第三方 API、支付处理器),无法参与事务。
  • 长时运行的工作流,持有分布式锁不现实。
  • 业务对“如果步骤 X 失败,就运行步骤 X' 来撤销”有明确概念。

不适用的情况

  • 一切都在单个服务或单个聚合内完成——应使用本地数据库事务。
  • 各步骤是幂等且与顺序无关的——可能根本不需要 Saga 的协调。
  • 确实需要“原子”回滚语义(在分布式系统中罕见)——Saga 不提供这种语义;它提供的是带补偿的最终一致性。

主要能力

两种风格,不同的协调形态

编排式 Saga。 每个服务监听事件并决定何时行动。服务 A 完成步骤 1 后发出 Step1Completed;服务 B 接收后完成步骤 2 并发出 Step2Completed,依此类推。补偿同样以事件形式发出(Step1Compensated)。

  • 优点:去中心化、无单点故障、可横向扩展。
  • 缺点:整个工作流是隐式的——无人拥有它;调试卡住的 Saga 很困难;新增一个步骤会触及多个服务。

协同式 Saga(流程管理器)。 由中央协调器驱动工作流。它依次向每个服务发送命令,监听它们的响应,并决定下一步(继续前进或执行补偿)。

  • 优点:工作流显式、集中在一处,易于推理和测试。
  • 缺点:协调器是一个必须高度可用的协调组件;集中化是实实在在的成本。

补偿动作,而非回滚

回滚(数据库事务)会把状态恢复到好像什么都没发生。补偿动作则撤销业务效果。退款是一种补偿;如果支付已经完成,回滚支付是不存在的。

  • 补偿必须是幂等的,并且在部分完成后调用也安全。
  • 有些动作无法补偿(发送了邮件、调用了外部不可逆的 API)。应把这类步骤设计在最后,这样 Saga 中更早的失败永远不会触及它们。

幂等性与至少一次投递

Saga 生活在事件驱动的世界里。消息可能被重新投递。每个步骤和每个补偿都必须是幂等的。

Saga 状态

协调器(或在编排式中,分散在各服务中)追踪每个 Saga 实例所处的位置。需要持久化这一状态——Saga 崩溃会发生,你需要能够恢复。

使用方式(决策启发式)

  • ≤3 步且参与者稳定 → 编排式。
  • 4+ 步,或以后可能新增步骤,或补偿逻辑不平凡 → 协同式。
  • 对步骤排序,使不可逆的步骤排在最后。
  • 从第一天起就把幂等性构建进每个步骤。
  • 持久化协调器状态;重启时重新加载。
  • 当复杂度需要时,使用工作流引擎(Temporal、Camunda、Conductor)而非自己手写协调器——但要审慎使用;它们是实实在在的依赖。

反模式

  • 名为“Saga”实为链式同步 RPC。服务 A 调用 B,B 调用 C,没有事件代理。那是分布式调用链,不是 Saga;失败不会补偿,只会向上传播。
  • 并不是真正补偿的“补偿动作”。把记录标记为“已取消”而不是给用户退款。只撤销一半。
  • 非幂等的步骤。同一消息被重新投递 → 步骤运行两次 → 用户被扣款两次。
  • 不可逆步骤放在中间。步骤 3 发送了一封无法撤回的邮件;步骤 4-5 失败;你无法撤销那封邮件。应把它放在最后。
  • 20 步的 Saga。那大概率应该是工作流引擎,而不是手写的 Saga。

适用场景

分布式系统中的跨服务业务事务,尤其是微服务架构下“如何跨服务进行事务”的标准答案。事件驱动架构、事件溯源常与 Saga 配合使用。

限制与相关技能

  • 不提供原子回滚,只提供带补偿的最终一致性。
  • 相关:arch-event-driven(Saga 事件流经代理)、arch-microservices(Saga 是跨服务事务的标准答案)、arch-event-sourcing(Saga 状态常被事件溯源)、arch-circuit-breaker(调用其他服务的 Saga 步骤应自我保护)、ddd-domain-event(Saga 步骤产生/消费领域事件)。

参考文献

  • Hector Garcia-Molina & Kenneth Salem, "Sagas" (1987) —— 原始论文。
  • Khononov, Learning DDD,微服务/事件驱动章节中关于 Saga 的部分。
  • Bellemare, Building Event-Driven Microservices,第 8 章(Building Workflows with Microservices)。