分布式事务鉴权拦截的Saga状态持久化实现方案 - 第2节
Saga 执行流程:正向补偿与逆向回滚
Saga 是一种长活事务(Long-Running Transaction, LRT)模式,它将一个全局事务拆分为多个本地事务(子事务),每个子事务都对应一个正向操作(T₁, T₂, …, Tₙ)和一个补偿操作(C₁, C₂, …, Cₙ)。Saga 的核心执行流程分为两种路径:正向补偿(全部成功)与逆向回滚(部分失败)。
正向补偿流程(Happy Path)
- 顺序执行:编排器或协同消息驱动依次调用 T₁, T₂, …, Tₙ。
- 本地提交:每个子事务执行完成后立即提交本地数据库,释放锁资源。
- 状态持久化:每完成一个子事务,将当前状态(如
COMPENSATING/COMPLETED)写入 Saga 日志表。 - 全局完成:所有 Tₙ 执行成功,Saga 标记为
FINISHED,无需调用任何补偿操作。
逆向回滚流程(Compensating Path)
- 失败检测:子事务 Tₖ 执行失败(业务异常、超时、网络中断)。
- 触发补偿:编排器或协同机制立即启动逆向补偿,按逆序调用 Cₖ₋₁, Cₖ₋₂, …, C₁。
- 幂等补偿:每个补偿操作必须幂等,确保重复调用不产生副作用。
- 状态标记:补偿完成后,Saga 日志记录
ROLLBACK状态,全局事务回滚完成。
关键原则:补偿操作必须能够语义上撤销正向操作的效果,而非简单的数据库回滚。例如,正向操作为“扣减库存”,补偿操作应为“增加库存”;正向操作为“发送邮件”,补偿操作可为“发送撤销邮件”或记录已撤销状态。
Saga 编排器(Orchestrator)与协同(Choreography)模式对比
Saga 的两种主流实现模式——编排器(Orchestrator)与协同(Choreography)——在控制流、耦合度、可维护性等方面存在显著差异。选择哪种模式取决于系统规模、团队能力和事务复杂度。
编排器模式(Orchestrator)
- 核心思想:引入一个中央编排器(Orchestrator)对象,负责协调所有子事务的执行顺序、失败检测和补偿调度。
- 控制流:编排器通过命令/事件驱动各参与者,参与者只响应编排器的指令,不感知其他参与者。
- 状态管理:编排器集中维护 Saga 状态,便于持久化和监控。
- 优点:流程清晰、易于调试、适合复杂事务(如嵌套 Saga、条件分支)。
- 缺点:编排器成为单点瓶颈,增加系统耦合度。
协同模式(Choreography)
- 核心思想:没有中央协调者,每个子事务完成后通过事件(Event)触发下一个子事务。
- 控制流:参与者之间通过消息队列(如 Kafka、RabbitMQ)异步通信,形成事件链。
- 状态管理:状态分散在各参与者本地,需通过事件溯源或分布式追踪还原全局状态。
- 优点:去中心化、高可扩展性、适合微服务松耦合场景。
- 缺点:流程隐式、调试困难、补偿逻辑分散,容易形成“事件风暴”。
| 对比维度 | 编排器模式(Orchestrator) | 协同模式(Choreography) |
|---|---|---|
| 控制中心 | 中央编排器 | 无中心,事件驱动 |
| 耦合度 | 参与者与编排器耦合 | 参与者之间松耦合 |
| 状态持久化 | 集中存储在 Saga 日志表 | 分散在事件存储或本地日志 |
| 调试难度 | 低(流程可见) | 高(需追踪事件链) |
| 扩展性 | 编排器可能成为瓶颈 | 天然支持水平扩展 |
| 适用场景 | 复杂事务、需要严格顺序控制 | 简单线性事务、高吞吐场景 |
| 典型实现 | Axon Framework、Camunda、自研编排器 | Eventuate Tram、Kafka Streams、自研事件总线 |
选型建议:如果团队对事务流程有强管控需求,且愿意接受一定的中心化风险,优先选择编排器模式;如果系统追求极致松耦合和弹性伸缩,且事务链路简单(通常不超过 5 步),协同模式更合适。
模式选择决策树
在实际项目中,可以通过以下决策树快速判断采用哪种模式:
- 事务步骤是否超过 5 个? → 是 → 编排器模式;否 → 继续判断。
- 是否需要动态条件分支或嵌套 Saga? → 是 → 编排器模式;否 → 继续判断。
- 团队是否熟悉事件驱动架构? → 是 → 协同模式;否 → 编排器模式。
- 系统是否要求极致松耦合和独立部署? → 是 → 协同模式;否 → 编排器模式。
常见陷阱:在协同模式中,如果事件顺序依赖严格的时间戳或全局 ID,容易因网络延迟导致乱序。建议在事件体中携带序列号或前驱事件 ID,并在消费者端做顺序校验。编排器模式则需注意编排器自身的高可用和幂等性设计,避免编排器宕机导致 Saga 状态丢失。