5.3.3 SAGA
SAGA 事务模式历史悠久,早于分布式事务概念的提出。
SAGA 起源于 1987 年普林斯顿大学的 Hector Garcaa-Molina 和 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 必须成功(使用最大努力交付机制)。
图 5-4 SAGA 事务模型
SAGA 模式非常适合处理流程较长且需要确保事务最终一致性的业务操作。例如,一个旅游预订平台上,用户可以同时预订机票、酒店和租车服务,这三项服务可能由不同的微服务或第三方供应商提供。这个场景中,SAGA 事务模型允许系统逐步执行每个操作,并在任一步骤失败时有序地进行补偿操作,从而确保系统的一致性和提升用户体验。
与 TCC 模型相比,SAGA 通常采用事件驱动设计,即每个服务都是异步执行的,无需设计资源的冻结状态或处理撤销冻结的操作。然而,这种方式也存在一些问题。比如,缺乏隔离性,当多个 SAGA 事务同时操作同一数据源时,因缺乏隔离机制,操作无法保证原子性,可能导致数据被覆盖的情况。
最后,尽管补偿操作相对容易实现,但确保正向操作和逆向回滚的严格执行也需要投入相当多的精力。因此,SAGA 事务通常不会通过裸编码来实现,而是在事务中间件的支持下完成。前面介绍 TCC 事务模型时,笔者提到的 Seata 中间件也支持 SAGA 事务模型。
参见 https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf ↩︎