5.3.3 SAGA

SAGA 的英文中有“长篇故事、长篇记叙、一长串事件”的含义,SAGA 事务模式的历史十分悠久,早于分布式事务概念的提出,它源于 1987 年普林斯顿大学的 Hector Garcaa-Molrna 和 Kenneth Salem 在 ACM 发表的一篇论文”SAGAS“[1],论文中提出了一种如何提升”长时间事务“(Long Lived Transaction)运作效率的方法,大致的思路是把一个大事务分解成多个可交错运行的子事务集合,并在每个子事务中引入补偿操作

提出 SAGA 的目的原本是为了避免大事务长时间锁定数据库的资源,后来逐渐发展成将一个分布式环境中的大事务,分解为一系列本地事务的设计模式。在 SAGA 模式下,分布式事务内有多个参与者,每一个参与者都是一个冲正补偿服务,需要用户根据业务场景实现其正向操作和逆向回滚操作。

SAGA 由两部分操作组成。

  • 一部分是将大事务 T 拆分成若干小事务,命名为 T1,T2,Tn。每个子事务被应被视为原子行为,如果分布式事务 T 能够正常提交,那么它对数据的影响(最终一致性)就应该与连续按顺序成功提交子事务 Ti 等价。
  • 另一部分是为每个子事务设计对应的补偿动作,命名为 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 必须成功(持续重试,最大努力交付)。

SAGA 模式非常适用于流程长,且需要保证事务最终一致性的业务操作。例如,在微服务架构中,一个业务通过要跨越多个微服务实现,就比较适合 SAGA 模式, 与 TCC 相比,SAGA 通常基于事件驱动设计,即每个服务都是异步执行,不需要为资源设计冻结状态和撤销冻结相关的操作,但这种方式也存在一些问题,比如缺乏隔离性,当多个 SAGA 事务操作同一个数据源的时,缺乏隔离性会导致操作不是原子性,可能会出现数据被覆盖的情况。

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


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

Last Updated:
Contributors: isno