专栏首页潜行前行10分钟说透Saga分布式事务

10分钟说透Saga分布式事务

开篇

随着微服务架构的兴起,越来越多的公司会在实际场景中遇到分布式事务的问题。特别是在金融应用场景,几个跨进程的应用共同完成一个任务,就更离不开分布式事务的参与。而对于分布式事务而言,2PC、TCC也是经常被提到了,不过在面对长业务流程,并且很难进行TCC改造的场景,会选择使用Saga分布式事务。今天会给大家介绍Saga实现分布式事务的内容:

  • Saga的分布式解决方案
  • Saga处理事务一致性
  • Saga分布式事务协调

Saga的分布式解决方案

随着互联网的快速发展,原来的单体应用已经很难支撑大流量高并发的请求了,因此软件系统由原来的单体应用逐渐向分布式过度,如图1所示,左边的Web App 包含了UI和服务的模块,在转变以后会对应右边的微服务架构,服务之间存在关联地相互调用。

图1 单体到分布式的系统架构过渡

在进行分布式部署之后,会存在多个服务共同完成一个事务操作,并且这些服务彼此都存在于不同的服务器或者网络环境,服务之间需要通过网络远程协作完成事务称之为分布式事务。例如:银行转账业务、下单扣件库存等。

在分布式事务场景下,如果对数据有强一致性要求,会在业务层上才去“两阶段提交”(2PC)的方案。

如果保证最终一致性的话可以采取TCC (Try Confirm Cancel)模式。虽然TCC保证最终一致性的模式被业内广泛使用,但是对于某些分布式事务场景,流程多、流程长、还可能要调用其它公司的服务。特别是对于不可控的服务(其他公司的服务),这些服务无法遵循 TCC 开发模式,导致TCC模式的开发成本增高。体现在具体场景中,以金融核心的业务为代表(渠道层、产品层、集成层),其特点是:流程多、流程长、调用不可控服务。同时也是应为流程长,事务边界太长,加锁时间长,使用TCC模式会影响并发性能。

鉴于此类业务场景的分布式事务处理,提出了Saga分布式处理模式。Saga是一种“长事务的解决方案”,更适合于“业务流程长、业务流程多”的场景。特别是针对参与事务的服务是遗留系统服务,此类服务无法提供TCC模式下的三个接口,就可以采用Saga模式。

其适用于的业务业务场景有,金融机构对接系统(需要对接外部系统)、渠道整合(流程长)、分布式架构服务等。其优势是一阶段提交本地事务,无锁,高性能;参与者可异步执行,高吞吐;补偿服务易于实现,因为一个更新操作的反向操作是比较容易理解的;当然其也存在缺点,就是不保证隔离性。

Saga处理事务一致性

1987年普林斯顿大学的Hector Garcia-Molina和Kenneth Salem发表了一篇Paper Sagas,讲述的是如何处理long lived transaction(长活事务)。Saga是一个长活事务可被分解成可以交错运行的子事务集合。其中每个子事务都是一个保持数据库一致性的真实事务。

在这位老兄的论文中提到,每个Saga由一系列sub-transaction Ti组成。每个Ti都有对应的补偿动作Ci,补偿动作用于撤销Ti造成的结果。这里可以理解为,针对每一个分布式事务的每个执行操作或者是步骤都是一个 Ti,例如扣减库存是T1、创建订单是T2、支付服务是T3。那么针对每个Ti都对应一个补偿动作Ci,例如回复库存C1、订单回滚C2、支付回滚C3。

Saga事务有两种恢复策略:

向前恢复(forward recovery),也就是“勇往直前”。

对于执行不通过的事务,会尝试重试事务,这里有一个假设就是每个子事务最终都会成功。这种方式适用于必须要成功的场景,如图2 所示,上面的图例,子事务按照从左到右的顺序执行,T1执行完毕以后T2 执行,然后是T3、T4、T5。

图2 Saga事务执行的策略

事务恢复的顺序也是按照:T1、T2、T3、T4、T5的方向进行,如果在执行T1的时候失败了就重试T1,以此类推在哪个子事务执行时失败了就执行哪个事务。因此叫做“勇往直前”。

向后恢复(backward recovery),在执行事务失败时,补偿所有已完成的事务,是“一退到底”的方式。如图2所示,下面的图例,子事务依旧从左往右执行,在执行到事务T3的时候,该事务执行失败了,于是按照红线的方向开始执行补偿事务,先执行C3、然后是C2和C1,直到T0、T1、T2的补偿事务C1、C2、C3都执行完毕。也就是回滚整个Saga的执行结果。

Saga分布式事务协调

上面介绍了Saga的概念和事务恢复方式,每个事务存在多个子事务,每个子事务都有一个补偿事务,其在事务回滚的时候使用。由于子事务对应的操作在分布式的系统架构中会部署在不同的服务中,这些子事务为了完成共同的事务需要进行协同。

实际上在启动一个Saga事务时,协调逻辑会告诉第一个Saga参与者,也就是子事务,去执行本地事务。事务完成之后Saga的会按照执行顺序调用Saga的下一个参与的子事务。这个过程会一直持续到Saga事务执行完毕。

如果在执行子事务的过程中遇到子事务对应的本地事务失败,则Saga会按照相反的顺序执行补偿事务。通常来说我们把这种Saga执行事务的顺序称为个Saga的协调逻辑。这种协调逻辑有两种模式,编排(Choreography)和控制(Orchestration)分别如下:

编排(Choreography):参与者(子事务)之间的调用、分配、决策和排序,通过交换事件进行进行。是一种去中心化的模式,参与者之间通过消息机制进行沟通,通过监听器的方式监听其他参与者发出的消息,从而执行后续的逻辑处理。由于没有中间协调点,靠参与靠自己进行相互协调。

控制(Orchestration):Saga提供一个控制类,其方便参与者之前的协调工作。事务执行的命令从控制类发起,按照逻辑顺序请求Saga的参与者,从参与者那里接受到反馈以后,控制类在发起向其他参与者的调用。所有Saga的参与者都围绕这个控制类进行沟通和协调工作。

下面通过一个例子来介绍这两种协调模式,假设有一个下单的业务,从订单服务的创建订单操作发起,会依次调用支付服务中的支付订单,库存服务中的扣减库存以及发货服务中的发货操作,最终如果所有参与者(服务)中的操作(子事务)完成的话,整个下单事务就算完成。

编排(Choreography),由于没有中心的控制类参与参与者操作之间的协调工作,因此通过消息发送的方式进行协调。

如图3所示:

图3 编排模式-事务执行成功

1. “订单服务”中执行“创建订单”操作,此时会发送一个“创建订单消息”到队列中。

2. “支付服务”监听到队列中的这个订单消息,调用“支付订单”的操作,同时也发送“只服务消息”到队列中。

3. “库存服务”在监听到“支付消息”之后会进行“扣减库存”的处理,并且发送“扣减库存消息”等待下一个消费者接受。

4. “发货服务”作为整个事务的最后一个子事务,在接到“扣减库存消息”以后会执行发货的子事务,完成事务以后会给“订单服务”发送“发货消息”,订单服务在接受到消息以后完成整个事务闭环,并且提交。

上面说的是事务执行成功的情况,如果事务执行失败那应该如何处理?

如图4所示:

图4 编排模式-事务执行失败

1. 假设在执行“发货”时子事务失败了,会发送“发货失败消息”。

2. 库存服务在接受到“发货失败消息”之后会执行“回滚库存”的操作,该操作将原来扣减的库存加回去,同时发送“扣减失败消息”。

3. “支付服务”在接受到“扣减失败消息”之后会执行“回滚支付”,进行退款的操作,同时发送“支付失败消息”。订单服务在接受到该消息以后将下单事务标记为失败。

从上面的描述可以看出编排的好处

简单:每个子事务进行操作时只用发布事件消息,其他子事务监听处理。

松耦合:参与者(服务)之间通过订阅事件进行沟通,组合会更加灵活。

当然也有一些缺点

理解困难:没有对业务流程进行完整的描述,要了解整个事务的执行过程需要通过阅读代码完成。增加开发人员理解和维护代码的难度。

存在服务的循环依赖:由于通过消息和事件进行沟通,参与者之间会存在循环依赖的情况。也就是A服务调用B服务,B服务又调用A服务的情况。这也增加了架构设计的复杂度,在设计初期需要认真考虑。

紧耦合风险:每个参与者执行的方法都依赖于上一步参与者发出的消息,但是上一步的参与者的所有消息都需要被订阅,才能了解参与者的真实状态,无形中增加了两个服务的耦合度。

控制(Orchestration),其核心是定义一个控制类,它会告诉参与者(服务)应该执行哪些操作(子事务)。 Saga控制类通过命令以及异步回复的方式与参与者进行交互。

如图5所示:

图5 控制模式-成功

1. 订单服务执行下单事务时,向Saga协调器发送请求命令,Saga协调器接受到命令以后按照子事务执行的顺序调用服务中的方法。

2. 最开始执行“支付订单”的操作,调用“支付服务”中的“支付订单”操作,并且通过虚线的部分返回执行结果“支付完成”。

3. 接下来,执行“库存服务”中的“扣减库存”方法,同样通过虚线部分返回扣减完成的消息给“请求反馈“模块。

4. 紧接着就是执行“发货“命令,调用”发货服务“中的”发货“方法,并且返回”发货完成“的响应。

5. 最后,三个子事务都执行完毕以后,返回订单服务,完成整个分布式事务。

介绍完成成功完成事务之后,再来看看出现异常的情况。

如图6所示:

图6 控制模式-失败

1. 在执行“发货”命令时发现“发货失败”,于是“发货服务”反馈给Saga协调器。

2. 此时协调器调用“库存服务”中的“回滚库存”操作,将扣减的库存恢复。

3. 然后调用“支付服务”中的“回滚支付”完成支付退款的工作。

4. 最后,通知订单服务事务处理失败。

需要指出的是控制模式也是基于事件驱动的,与编排模式一样会发送消息通知参与者执行命令,上面两个图中命令的执行和调用也是通过消息的方式进行。

控制器设计的优点:

避免循环依赖:在编排模式中存在参与者之间的循环调用,而中心控制类的方式可以避免这种情况的发生。

降低复杂性:所有事务交给控制器完成,它负责命令的执行和回复的处理,参与者只需要完成自身的任务,不用考虑处理消息的方式,降低参与者接入的复杂性。

容易测试:测试工作集中在集中控制类上,其他服务单独测试功能即可。

容易扩展:如果事务需要添加新步骤,只需修改控制类,保持事务复杂性保持线性,回滚更容易管理。

当然这种方法也存在缺点

依赖控制器:控制器中集中太多逻辑的风险。

增加管理难度:这种模式除了管理各个业务服务以外,还需要额外管理控制类服务,无形中增加了管理的难度和复杂度。而且存在单点风险,一旦控制器出现问题,整个业务就处于瘫痪中。

总结

这里对Saga进行一个总结,首先Saga是针对分布式长活事务的解决方案,针对事务长、多、复杂的情况,特别是服务由多个公司开发具有不可控性,可以使用Saga模式进行分布式事务的处理。Saga在处理事务一致性方面采取了向前恢复和向后恢复策略,前者通过不断重试的方式保证事务完成,而后者通过子事务的补偿事务,逐一回滚的方式让事务标记失败。在分布式协调方面,Saga采用了两种模式:编排和控制。前者让参与者(服务)之间通过消息进行沟通,根据事件出发事务的执行流程,是一种去中心化的模式。后者通过中心控制类,处理事务的执行和回滚步骤,统一调用服务和接受服务的反馈。

END

本文分享自微信公众号 - 潜行前行(qianxingcsc)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-06-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Saga分布式事务

    说到分布式事务,大部分人都会知道ACID,两阶段提交,TCC等常见模式。 在微服务大行其道的今天,基于Saga实现的分布式事务则更具普适性。

    春哥大魔王
  • 10 分钟看懂分布式事务

    什么是分布式事务 问题的引出 先看一张图,一个电商平台的架构图。 ? 对于用户来说的一个创建订单的过程,背后很可能跨越了多个应用服务。涉及诸如:订单、库存、...

    linxinzhe
  • 微服务分布式事务Saga模式简介

    物流IT圈
  • 分布式柔性事务之Saga详解

    Saga模型起源于1987年 Hector Garcia-Molina,Kenneth Salem 发表的论文《Sagas》,是分布式事务相关概念最早出现的。

    孙玄@奈学教育
  • 源码解析之Seata项目中的分布式ID生成算法

    Saga作为阿里开源的长事务解决方案,涉及到全局事务id的生成和串联,需要保证事务id的稳定性和全局唯一性。

    Coder的技术之路
  • 分布式事务系列--是选TCC还是SAGA

    这种模式下,我们需要操作的目标字段,都要添加一个相关的冻结字段,try操作是操作冻结字段,cc操作时,将冻结的数值更新到目标字段。 示例如下:

    IT云清
  • Saga分布式事务解决方案与实践

    我先介绍一下我自己,我叫姜宁,来自于华为开源研究中心,现在负责的是ServiceComb这个开源项目。ServiceComb这个项目已经进到Apache孵化,应...

    程序员小王
  • Apache ShardingSphere开源分布式数据库中间件应用详解

    相比于数据分片方案的逐渐成熟,集性能、透明化、自动化、强一致、并能适用于各种应用场景于一体的分布式事务解决方案则显得凤毛麟角。基于两或三阶段提交的分布式事务的性...

    京东技术
  • 目前最好用的开源分布式事务解决方案之一

    相比于数据分片方案的逐渐成熟,集性能、透明化、自动化、强一致、并能适用于各种应用场景于一体的分布式事务解决方案则显得凤毛麟角。基于两(三)阶段提交的分布式事务的...

    芋道源码
  • 五分钟学会分布式事务

    孙玄@奈学教育
  • 刚柔并济的开源分布式事务解决方案

    张亮,京东数科数据研发负责人,Apache ShardingSphere发起人 & PPMC

    纯洁的微笑
  • 我说分布式事务之TCC

    接触分布式相关的开发已经有一段时间了,自然绕不开分布式事务。从本文开始,我将带领大家了解常见的分布式事务的解决方案,深入原理,浅出实践,让我们在今后的开发中对分...

    程序猿DD
  • 分布式事务,一次性说清

    的确,分布式事务的落地实践相对比较复杂,和数据库分库分表一样,很多公司采取的策略都是能不碰就不碰,因为在业务规模不庞大时,设计分布式事务要投入的精力,可能比采取...

    架构师之路
  • 周末带你吃透分布式事务

    分布式事务属于非常重要的一个知识点,难度也比较高,整理一套分布式事务的视频,大家可以周末看一下,一定要反复看,消化掉,有不理解的可以加我微信聊。

    路人甲Java
  • 分布式事务、分布式锁、分布式session

    来源 | cnblogs.com/heqiyoujing/p/10917102.html

    程序猿DD
  • 分布式架构设计篇(九)-柔性事务之Saga详解

    ​ Saga模型起源于1987年 Hector Garcia-Molina,Kenneth Salem 发表的论文《Sagas》,是分布式事务相关概念...

    林淮川
  • 领域驱动设计(DDD)实践之路(二):事件驱动与CQRS

    这是“领域驱动设计实践之路”系列的第二篇文章,分析了如何应用事件来分离软件核心复杂度。探究CQRS为什么广泛应用于DDD项目中,以及如何落地实现CQRS框架。当...

    2020labs小助手
  • 分布式事务

    https://juejin.im/post/5b5a0bf9f265da0f6523913b

  • 分布式事务

    不知道你是否遇到过这样的情况,去小卖铺买东西,付了钱,但是店主因为处理了一些其他事,居然忘记你付了钱,又叫你重新付。又或者在网上购物明明已经扣款,但是却告诉我没...

    用户3467126

扫码关注云+社区

领取腾讯云代金券