saga

saga
强烈推介IDEA2021.1.3破解激活,IntelliJ IDEA 注册码,2021.1.3IDEA 激活码  

大家好,我是架构君,一个会写代码吟诗的架构师。今天说一说saga,希望能够帮助大家进步!!!

什么是saga

由于微服务架构中,每个服务都是独立的数据库,但是系统中的数据一致性是必须的,saga模式就是保证系统中数据一致性而设计的
本篇以订单服务为例解释saga服务

生成订单的整个流程

该流程共有4个服务,分别为订单服务(生成订单),用户服务(验证用户权限),账户服务(付钱之类),后厨服务

Created with Raphaël 2.2.0 订单流程 订单服务创建1个审批等待的订单 用户服务验证该用户是否可以下 账户服务提供用户付费的授权操作 后厨服务把订单状态改为等待接受 状态 订单服务把订单状态改为接受状态 结束

saga中的两种协调模式

在订单流程中,每个步骤的成功或失败都要通过saga协调,成功进行下一个步骤,失败则需要修改从此步骤以上的一些状态,比如授权状态失败,则订单状态改为订单生成失败状态。进行这种协调有两种方式,一种是协同模式,一种是编排模式。

协同模式

在每个单独的服务中都有自己单独saga进行协调,它们都订阅彼此的服务通过服务事件返回信息来作出相应的响应。每一个参与订单流程的服务都要从订单服务(由下图可以看出总共有四个事件整个流程成环状)开始,更新其数据库和触发下个相应的服务。
它的工作流程为:

  1. 订单服务(order events)创建一个处于申请中(APPROVAL PENDING)状态的Order并发布订单创建(OrderCreated)事件。
  2. 用户服务(Consumer service)发起订单创建(OrderCreated)事件,验证消费者是否可以下订单,并发布 用户验证(ConsumerVerified)事件。
  3. 后厨(Kitchen service)消费(OrderCreated)事件,验证Order,创建一个处于创建中(CREATE PENDING)状态的后厨工单Ticket,并发布 (TicketCreated)事件
  4. 账户服务(Accounting Service)消费订单创建(OrderCreated)事件并创建一个处于等待(PENDING)状态下的信用卡验证(CreditCardAuthorization)。
  5. 账户服务(Accounting Service)消费TicketCreated和用户验证(ConsumerVerified)事件,向消费者的信用卡收费,并发布 信用卡验证(CreditCardAuthorized)事件。
  6. 后厨服务(Kitchen service)消费信用卡验证(CreditCardAuthorized)事件并将 Ticket的状态更改为等待接受状态(AWAITING ACCEPTANCE)。
  7. 订单服务(Order Service)接收 信用卡验证(CreditCardAuthorized)事件,将 Order的状态更改为接受(APPROVED),并发布订单接收 (OrderApproved)事件。

在这里插入图片描述

协同式Saga的好处和弊端

好处:

  1. 简单:服务在创建、更新或删除业务对象时发布事件。
  2. 松耦合:参与方订阅事件并且彼此之间不会因此而产生耦合。

弊端:

  1. 更难理解:与编排式不同,代码中没有一个单一地方定义了Saga。相反,协调式Saga的逻辑分布在每个服务的实现中。因此,开发人员有时很难理解特定的Saga是如何工作的。
  2. 服务之间的循环依赖关系:Saga参与方订阅彼此的事件,这通常会导致循环依赖关系虽然这并不一定是个问题,但循环依赖性被认为是一种不好的设计风格。
  3. 紧耦合的风险:每个Saga参与方都需要订阅所有影响它们的事件。例如,账户服务必须订阅所有可能导致消费者信用卡被扣款或退款的事件。因此,存在一种风险,即Accounting Service的内部代码需要与 Order Service实现的订单生命周期代码保持同步更新。

编排模式

开发者会定义一个saga的编排类,所有的服务都会在这个类中进行协调。saga编排器使用命令/异步响应方式与saga的参与方服务进行通信。
流程:

  1. Saga编排器向Consumer Service发送VerifyConsumer命令。
  2. Consumer Service回复ConsumerVerified消息。
  3. Saga编排器向 Kitchen Service发送CreateTicket命令。
  4. Kitchen Service回复 TicketCreated消息。
  5. Saga编排器向Accounting Service发送AuthorizeCard消息。
  6. Accounting Service使用CardAuthorized消息回复。
  7. Saga编排器向Kitchen Service发送ApproveTicket命令。
  8. Saga编排器向Order Service发送ApproveOrder命令。

在这里插入图片描述

把saga的编排模式视为一个状态机

状态机是建模Saga编排器的一个好方法。状态机由一组状态和一组由事件触发的状态之间的转换组成。每个转换都可以有一个动作,对Saga来说动作就是对某个参与方的调用。状态之间的转换由Saga参与方执行的本地事务完成触发。当前状态和本地事务的特定结果决定了状态转换以及执行的动作(如果有的话)。对状态机也有有效的测试策略。因此,使用状态机模型可以更轻松地设计、实现和测试Saga。
状态机的初始操作是向Consumer Service发送VerifyConsumer命令。来自Consumer Service的响应触发下一个状态转换。如果Consumer被成功验证,saga将创建ticket并转换到creatingticket状态。但是,如果Consumer验证失败,saga将拒绝订单并转换到rejecting order状态。在saga参与者的响应驱动下,状态机经历了许多其他的状态转换,直到它达到一个最终状态,即订单批准或订单拒绝。
在这里插入图片描述

编排式Saga的好处和弊端

好处:

  1. 更简单的依赖关系:编排的一个好处是它不会引人循环依赖关系。Saga编排器调用Saga参与方,但参与方不会调用编排器。因此,编排器依赖于参与方,但反之则不然,因此没有循环依赖。
  2. 较少的耦合:每个服务实现供编排器调用的API,因此它不需要知道Saga参与方发布的事件。
  3. 改善关注点隔离,简化业务逻辑:Saga的协调逻辑本地化在Saga编排器中。领域对象更简单,并且不需要了解它们参与的Saga。业务更加简单。

弊端:

  1. 在编排器中存在集中过多业务逻辑的风险。这会导致这样的架构设计:智能编排器告诉哑服务要做什么操作。幸运的是,你可以通过设计只负责排序的编排器来避免此问题,并且不包含任何其他业务逻辑。

隔离问题

ACID事务的隔离属性可确保同时执行多个事务的结果与顺序执行它们的结果相同。数据库为每个ACID事务提供了具有对数据的独占访问权的错觉。隔离使得编写并发执行的业务逻辑变得更加容易。

使用Saga的挑战在于它们缺乏ACID事务的隔离属性。这是因为一旦该事务提交,每个Saga的本地事务所做的更新都会立即被其他 Sagas看到。此行为可能导致两个问题。首先,其他Saga可以在执行时更改该Saga所访问的数据。其他Saga可以在Saga完成更新之前读取其数据,因此可能会暴露不一致的数据。

所以可以理解为saga只满足ACID中的ACD。下面简单介绍一下ACID

  • A atomicity 原子性 一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作,这就是事务的原子性
  • C consistency 一致性 事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。
  • I isolation 隔离性 在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。不同的事务并发操作相同的数据时,每个事务都有各自完成的数据空间,即一个事务内部的操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰。
  • D durability 持久性 一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。

缺乏隔离性导致的问题

  1. 丢失更新:一个Saga没有读取更新,而是直接覆盖了另一个Saga所做的更改。
  2. 脏读:一个事务或一个Saga读取了尚未完成的Saga所做的更新。
  3. 模糊或不可重复读:一个Saga的两个不同步骤读取相同的数据却获得了不同的结果,因为另一个Saga已经进行了更新。

saga结构

在这里插入图片描述
如图所示共有3种模型

  1. 可补偿性事务(Compensatable transactions):可以使用补偿事务回滚的事务。
  2. 关键性事务(Pivot transactions):Saga执行过程的关键点。如果关键性事务成功,则Saga将一直运行到完成。关键性事务不见得是一个可补偿性事务,或者可重复性事务。但是它可以是最后一个可补偿的事务或第一个可重复的事务
  3. 可重复性事务(Retriable transactions):在关键性事务之后的事务,保证成功。

对策1:语义锁

使用语义锁对策时,Saga的可补偿性事务会在其创建或更新的任何记录中设置标志。该标志表示该记录未提交且可能发生更改。该标志可以是阻止其他事务访问记录的锁,也可以是指示其他事务应该谨慎地处理该记录的一个警告。这个标志会被一个可重复的事务清除,这表示Saga成功完成;或通过补偿事务清除,这表示Saga发生了回滚。

对策2:交换式更新

一个简单的对策是将更新操作设计为可交换的。如果可以按任何顺序执行,则操作是可交换的。这种对策很有用,因为它可以避免更新的丢失。例如,扣款动作,-100元,回滚动作+100元。

对策3:悲观视图

处理缺乏隔离性的另一种方法是悲观视图。它重新排序Saga的步骤,以最大限度地降低由于脏读而导致的业务风险。例如,考虑先前用于描述脏读异常的场景。在这种情况下,Create Order Saga执行了可用信用额度的脏读,并创建了超过消费者信用额度的订单。为了降低发生这种情况的风险,此对策将重新排序 Cancel Order Saga。

Order Service:将Order状态更改为已取消。
Delivery Service:取消送货。
Customer Service:增加可用信用额度。
在这个重新排序的Saga版本中,在可重复性事务中增加了可用的信用额度,消除了脏读的可能性。

对策4:重读值

重读值对策可防止丢失更新。使用此计数器的Saga在更新之前重新读取记录,验证它是否未更改,然后更新记录。如果记录已更改,则Saga将中止并可能重新启动。此对策是乐观脱机锁模式的一种形式。
Create Order Saga可以使用此对策来处理Order在批准过程中被取消的情况。批准Order的事务验证Order是否保持不变,因为它是在Saga早期创建的。如果不变,事务将批准 Order。但是,如果Order已被取消,则事务将中止该Saga,从而触发其补偿事务执行。

对策5:版本文件

版本文件对策之所以如此命名,是因为它记录了对数据执行的操作,以便可以对它们进行重新排序。这是将不可交换操作转换为可交换操作的一种方法。要了解此对策的工作原理,请考虑 Create Order Saga与 Cancel Order Saga同时执行的场景。除非Saga使用语义锁对策,否则 Cancel Order Saga可能会在 Create Order Saga授权信用卡之前取消消费者信用卡的授权。
Accounting Service处理这些无序请求的一种方法是在操作到达时记录操作,然后以正确的顺序执行操作。在这种情况下,它将首先记录 Cancel Authorization请求。然后,当 Accounting Service收到后续的 Authorize Card请求时,它会注意到它已经收到 Cancel Authorization请求并跳过授权信用卡。

对策6:业务风险评级

最终的对策是基于价值(业务风险)对策。这是一种基于业务风险选择并发机制的策略。使用此对策的应用程序使用每个请求的属性来决定使用Saga和分布式事务。它使用Saga执行低风险请求,可能会应用前几节中描述的对策。但它使用分布式事务来执行高风险请求(例如涉及大量资金)。此对策使应用程序能够动态地对业务风险、可用性和可伸缩性进行权衡。

参考https://blog.csdn.net/ylnlp5602260/article/details/113809953#t25

本文来源it小白求知路,由架构君转载发布,观点不代表Java架构师必看的立场,转载请标明来源出处:https://javajgs.com/archives/29155

发表评论