• 分布式事务(四)———SAGA 解决方案


    该系列参考:
    https://www.jianshu.com/p/962271bbf4ea
    https://blog.csdn.net/a745233700/article/details/122402303
    https://cloud.tencent.com/developer/article/2048776
    https://icyfenix.cn/

    简介

    SAGA 事务模式的历史十分悠久,还早于分布式事务概念的提出。它源于 1987 年普林斯顿大学的 Hector Garcia-Molina 和 Kenneth Salem 在 ACM 发表的一篇论文《SAGAS》(这就是论文的全名)。文中提出了一种提升“长时间事务”(Long Lived Transaction)运作效率的方法,大致思路是把一个大事务分解为可以交错运行的一系列子事务集合。原本 SAGA 的目的是避免大事务长时间锁定数据库的资源,后来才发展成将一个分布式环境中的大事务分解为一系列本地事务的设计模式

    一、核心原理

    在这里插入图片描述

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

    特点:补偿事务、最终一致性、不保证隔离性

    二、恢复策略

    如果 T1到 Tn均成功提交,那事务顺利完成,否则,要采取以下两种恢复策略之一:

    • 正向恢复(Forward Recovery):如果 Ti事务提交失败,则一直对 Ti进行重试,直至成功为止(最大努力交付)。这种恢复方式不需要补偿,适用于事务最终都要成功的场景,譬如在别人的银行账号中扣了款,就一定要给别人发货。正向恢复的执行模式为:T1,T2,…,Ti(失败),Ti(重试)…,Ti+1,…,Tn。
    • 反向恢复(Backward Recovery):如果 Ti事务提交失败,则一直执行 Ci对 Ti进行补偿,直至成功为止(最大努力交付)。这里要求 Ci必须(在持续重试后)执行成功。反向恢复的执行模式为:T1,T2,…,Ti(失败),Ci(补偿),…,C2,C1。

    从这里我们可以知道为什么SAGA一定要满足的三个条件了:

    • Ti与 Ci都具备幂等性:正向恢复下Ti有重试机制,反向恢复下Ci有重试机制
    • Ti与Ci交换律:Ci是Ti失败的补偿方案,假设Ti先执行(库存-10),Ci后执行补偿回滚(库存+10),假设因网络问题Ci先执行,Ti后执行,结果也要保持一致
    • Ci必须成功:这个很好理解,补偿方案如果不成功那就导致了数据一致性问题

    由于Saga事务不保证隔离性,所以补偿方案需要注意,并不是任何场景都能补偿的。比如:B给A转账100,A余额+100,B余额-100,本地事务提交成功了,分布式事务失败了需要回滚,而在回滚前A已经把余额全消费掉了,这时候肯定已经没办法进行补偿了。 (极端场景)

    三、实现方式

    1.基于事件的方式

    在基于事件的方式中,第一个服务执行完本地事务之后,会产生一个事件。其它服务会监听这个事件,触发该服务本地事务的执行,并产生新的事件。

    假设一个完整的订单流程包含了如下几个服务:

    • Order Service:订单服务
    • Payment Service:支付服务
    • Stock Service:库存服务
    • Delivery Service:物流服务

    采用基于事件的saga模式的订单处理流程如下:

    1. 订单服务创建一笔新订单,将订单状态设置为"待处理",产生事件ORDER_CREATED_EVENT
    2. 支付服务监听ORDER_CREATED_EVENT,完成扣款并产生事件BILLED_ORDER_EVENT
    3. 库存服务监听BILLED_ORDER_EVENT,完成库存扣减和备货,产生事件ORDER_PREPARED_EVENT
    4. 物流服务监听ORDER_PREPARED_EVENT,完成商品配送,产生事件ORDER_DELIVERED_EVENT
    5. 订单服务监听ORDER_DELIVERED_EVENT,将订单状态更新为"完成"。

    该模式下分布式事务的回滚

    每个需要回滚的服务都需要提供补偿操作的事件监听

    假设库存服务由于库存不足没能正确完成备货,我们可以按照下面的流程来回滚整个Saga事务:

    1. 库存服务产生事件PRODUCT_OUT_OF_STOCK_EVENT
    2. 订单服务和支付服务都会监听该事件并做出响应:
      1. 支付服务完成退款。
      2. 订单服务将订单状态设置为"失败"。

    该模式需要注意的点:

    1. 从事务入口就需要生成唯一的事务ID全局传递
    2. 每个服务都需要准备事务处理Log表,防止服务宕机事件丢失
    3. 要保证消息的可靠性,确保成功发送和成功消费 (类似本地消息事务表)
    4. 如业务允许完全可以不需要回滚监听,直接正向重试恢复
    5. 监听接口都需要保证幂等性
    6. 需要防止形成环形监听,也就是两个业务方相互监听对方事件

    2.基于状态机的方式

    DEMO详情见 : https://github.com/seata/seata-samples
    Seata文档详情见: https://seata.io/zh-cn/docs/overview/what-is-seata.html

    引入一个协调中心,所有需要参与事务的服务都与之交互,事务的流程状态都由协调中心控制
    这里直接可以看阿里的Seata Saga模式

    系列文章

  • 相关阅读:
    Redis内存回收机制-内存淘汰策略和过期策略
    一个 dubbo 和 springboot 的兼容性问题
    动态规划 | 斐波那契数列、爬楼梯 | leecode刷题笔记
    SQL----复杂查询
    Android学习笔记 53. 重新认识Android studio开发工具之创建项目
    期货择时策略-基于Hurst指数的分型策略研究
    5.1、nio-Bytebuffer内存结构
    车载通信架构 —— SOME/IP 协议概述
    关于研究鼠标绘制平滑曲线的阶段总结
    leetcode 63 不同路径II
  • 原文地址:https://blog.csdn.net/weixin_44102992/article/details/126593341