5.3.3 SAGA

SAGA 事务模式历史悠久,早于分布式事务概念的提出。它起源于 1987 年普林斯顿大学的 Hector Garcaa-Molina 和 Kenneth Salem 在 ACM 发表的论文《SAGAS》[1]。该论文提出了一种提高“长时间事务”(Long Lived Transaction)效率的方法,核心思路是将一个大事务分解为多个可以交错运行的子事务,并在每个子事务中引入补偿操作。

SAGA 最初的目的是避免大事务长时间占用数据库资源,后来发展成为一种在分布式环境中,将大事务分解为一系列小事务的设计模式。在 SAGA 模式下,分布式事务包含多个参与者,每个参与者都需要实现对应的正向操作和逆向回滚操作,根据具体业务场景进行补偿。

补偿

补偿指的是在分布式事务出现异常时,通过一系列的操作,尽可能使得分布式事务状态回滚到之前的状态,从而避免分布式事务产生不一致的情况。

SAGA 事务模型由两部分操作组成:

  1. 一部分是将大事务 T 拆分成若干小事务,命名为 T1,T2,Tn。每个子事务被应被视为原子行为,如果分布式事务 T 能够正常提交,那么它对数据的影响(最终一致性)就应该与连续按顺序成功提交子事务 Ti 等价。
  2. 另一部分是为每个子事务设计对应的补偿动作,命名为 C1,C2,Cn。Ti 与 Ci 满足以下条件:
    • Ti 与 Ci 具备幂等性。
    • Ti 与 Ci 满足交换律,即无论先执行 Ti 还是先执行 Ci,其效果都是一样的。
    • Ci 必须能成功提交,即不考虑 Ci 的失败回滚情况,如果出现失败持续重试直至成功或者被人工介入为止。

如果 T1 到 Tn 均执行成功,那么整个事务顺利完成,否则要根据下面两种恢复策略之一进行恢复。

  • 正向操作(Forward Recovery)如果 Ti 提交失败,则一直对 Ti 进行重试,直至成功为止(最大努力交付)。这种恢复方式不需要进行补偿,适用于事务最终都要执行成功的情况。例如订单服务中银行已经扣款,那么就一定要发货。
  • 逆向回滚(Backward Recovery)如果 Ti 提交失败,则执行对应的补偿 Ci,直至恢复到 Ti 之前的状态,这里要求 Ci 必须成功(持续重试,最大努力交付)。

图 5-4 SAGA 事务模型

SAGA 模式非常适用于流程长,且需要保证事务最终一致性的业务操作。例如,一个旅游预订平台,该平台允许用户在一次操作中预订机票、酒店和租车服务,这三项服务分别由不同的微服务或第三方供应商提供。在这个例子中,SAGA 事务模型允许系统逐步执行每个步骤,并且在任何一个步骤失败时,能够有条不紊地进行补偿操作,确保系统的一致性和用户体验。

与 TCC 相比,SAGA 通常基于事件驱动设计,即每个服务都是异步执行,不需要为资源设计冻结状态和撤销冻结相关的操作,但这种方式也存在一些问题。例如缺乏隔离性,当多个 SAGA 事务操作同一个数据源的时,缺乏隔离性会导致操作不是原子性,可能会出现数据被覆盖的情况。

最后尽管补偿操作容易实现,但保证正向操作和逆向回滚的严谨地进行也要花不少功夫,所以 SAGA 事务通常也不会通过裸编码实现,而是在事务中间件的基础上完成。笔者在前面介绍 TCC 事务模型时,提到的 Seata 中间件也支持 SAGA 事务模型。


  1. 参见 https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf ↩︎

总字数:1068
Last Updated:
Contributors: isno