首页 > 其他分享 >聊聊分布式解决方案Saga模式

聊聊分布式解决方案Saga模式

时间:2023-05-29 12:45:23浏览次数:43  
标签:事务 聊聊 TransitionTo Saga 状态机 实现 context 分布式

Saga模式

Saga模式使用一系列本地事务来提供事务管理,而一个本地事务对应一个Saga参与者,在Saga流程里面每一个本地事务只操作本地数据库,然后通过消息或事件来触发下一个本地事务,如果其中一个本地事务失败了,Saga就会执行一系列补偿事务来实现回滚操作。(补偿事务简单来讲就是对之前本地事务做的修改导致不一致的情况执行反向操作来消除掉不一致的状态)。

image

上图左侧是正常的事务流程,当执行事务T3时出现异常,则开始反向执行右边的事务补偿,其中C3是T3的补偿,C2是T2的补偿,C1是T1的补偿,将T3,T2,T1已经修改的数据做补偿处理。

实现分析

对Saga事务流程进行排序,当Ti事务完成之后,需要决定下一步要怎么进行。如果成功执行T(i+1)分支,如果失败,则执行C(i-1)分支。这类似一个工作流或是状态机的概念。从实现来看,有两种方式:

集中式实现

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

image

去中心化实现

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

image

实现比对

我个人认为在计算机的世界里没有银弹!任何的解决方案只能说是合适与不合适,而没有完美的契合并解决。

如上两种解决方式都有一定的弊端;对于集中式的实现方式,其弊端如下:

  • 必须额外实现一个协调器,相当于增加了系统复杂度
  • 需要考虑协调器自身发生故障时应对措施

分布式的实现方式,其弊端如下:

  • 添加新的事务步骤时比较麻烦,需要确定哪个Saga参与者订阅了哪个事件。
  • 有可能出现循环依赖的问题,每一个Saga参与者都可能订阅其他参与者的事件。
  • 集成测试异常复杂,需要运行所有服务来模拟事务。

实现方式

目前看到市面上已经有很多的saga实现,他们都具备saga的基本功能。

这些实现,可以大致可以分为两类

状态机实现
Seata

这一类的典型实现有seata的saga,他引入了一个DSL语言定义的状态机,允许用户做以下操作:

在某一个子事务结束后,根据这个子事务的结果,决定下一步做什么
能够把子事务执行的结果保存到状态机,并在后续的子事务中作为输入
允许没有依赖的子事务之间并发执行。

  • 优点:
    功能强大,事务可以灵活自定义

  • 缺点:
    状态机的使用门槛非常高,需要了解相关DSL,可读性差,出问题难调试。官方例子是一个包含两个子事务的全局事务,Json格式的状态机定义大约有95行,较难入门。
    接口入侵强,只能使用特定的输入输出接口参数类型,在云原生时代,对强类型的gRPC不友好(gRPC协议,在TM拿不到用户自定义的输入输出pb文件,因此无法解析结果中的字段)

Masstransit Saga State Machines

Masstransit是一个免费、开源的.NET 分布式应用框架。其功能之一就是提供了强大的状态机编排能力。通过集成消息队列中间件,基于C#高效易用的语法,支持了状态机的编排。其使用语法示例如下

///// 下单 初始化 → 已初始化
///// 翻译:当前状态是Initial且执行OrderProcessInitializationEvent事件时,Then(然后)执行xxxx,最后将状态转换(TransitionTo)为OrderProcessInitializedState

During(Initial,
    When(OrderProcessInitializationEvent)
        .Then(x => {
            x.Saga.OrderStartDate = DateTime.Now;
        })
        .TransitionTo(OrderProcessInitializedState));

///// 库存 已初始化 → 校验库存
///// 翻译:当前状态是OrderProcessInitializedState且执行CheckProductStockEvent事件时,Then(然后)执行xxxx,最后将状态转换(TransitionTo)为CheckProductStockState

During(OrderProcessInitializedState,
    When(CheckProductStockEvent)
    .Then(x => {
        System.Console.WriteLine(x.Message.OrderId);
        })
        .TransitionTo(CheckProductStockState));

///// 支付 校验库存 → 支付
During(CheckProductStockState,
    When(TakePaymentEvent)
        .TransitionTo(TakePaymentState));

///// 订单 支付 → 创建订单
During(TakePaymentState,
    When(CreateOrderEvent).Then(x => {
        System.Console.WriteLine(x.Message.OrderId);
    })
        .TransitionTo(CreateOrderState));

///// 创建订单失败
DuringAny(When(CreateOrderFaultEvent)
    .TransitionTo(CreateOrderFaultedState)
    .Then(context => context.Publish<Fault<TakePaymentEvent>>(new {context.Message})));

///// 支付失败
DuringAny(When(TakePaymentEventFaultEvent)
    .TransitionTo(TakePaymentFaultedState)
    .Then(context => context.Publish<Fault<CheckProductStockEvent>>(new {context.Message})));

///// 校验库存失败
DuringAny(When(CheckProductStockFaultEvent)
    .TransitionTo(CheckProductStockFaultedState)
    .Then(context => context.Publish<Fault<OrderProcessInitializationEvent>>(new {context.Message})));

///// 下单失败
DuringAny(When(OrderProcessInitializationFaultEvent)
    .TransitionTo(OrderProcessInitializedFaultedState)
    .Then(context => context.Publish<OrderProcessFailedEvent>(new {OrderId = context.Saga.CorrelationId})));

///// 下单流程失败
DuringAny(When(OrderProcessFailedEvent)
    .TransitionTo(OrderProcessFailedState));

流程逻辑:当客户端请求下单服务时,业务逻辑正常执行,执行成功后发布事件到消息队列,状态机监听到对应的订单事件后,修改当前状态,发布事件标识成功或失败,订单服务业务监听事件,响应状态的调整(一般是标识或回滚业务)。

image

  • 优点
    方便简单,而且强大,流程编排能力很强。

  • 缺点:引入了rabbitmq,有中间件依赖。

可参考实现:
使用 Masstransit中的 Request/Response 与 Courier 功能实现最终一致性
分布式事务 | 基于MassTransit的StateMachine实现Saga编排式分布式事务

非状态机实现

这一类的实现有eventuate的saga,dtm的saga。

在这一类的实现中,没有引入新的DSL来实现状态机,而是采用函数接口的方式,定义全局事务下的各个分支事务。

优点:

简单易上手,易维护

缺点:
难以做到状态机的事务灵活自定义

ACID与Saga

image

标签:事务,聊聊,TransitionTo,Saga,状态机,实现,context,分布式
From: https://www.cnblogs.com/zhiyong-ITNote/p/17440090.html

相关文章

  • 聊聊Python内函数的参数
    引:基于函数的定义与调用两个阶段,函数的参数也由此分为两块:形式参数和实际参数 形参与实参介绍函数的参数分为形式参数和实际参数,简称形参和实参:形参即在定义函数时,括号内声明的参数,形参本质就是一个变量名,用来接收外部传来的值;实参即在调用函数时,括号内传入的值,值可以是常......
  • 十三、利用分布式锁解决超卖问题
    库存超卖问题对于商城系统。超卖了一部分可以补获,12306对超卖问题更敏感。JMeter的使用  超卖演示&使用JMeter对购票功能进行压测  使用synchronized是否能解决库存超卖?超卖问题出现原因: 假设余票为1,此时多个线程同时查询到这条余票记录,并进行扣减,那么则会导致......
  • SpringCloudAlibaba整合分布式事务Seata
    目录1整合分布式事务Seata1.1环境搭建1.1.1Nacos搭建1.1.2Seata搭建1.2项目搭建1.2.1项目示意1.2.2pom.xml1.2.2.1alibaba-demo模块1.2.2.2call模块1.2.2.3order模块1.2.2.4common模块1.2.3配置文件1.2.3.1order模块1.2.3.2call模块1.2.4OpenFeign调用1.2.5order......
  • 微服务架构学习与思考(13):分布式配置中心
    一、配置中心的诞生用编程语言编写应用项目时,一般都会有项目的配置文件。比如用java编写项目,有一个properties的配置文件,会把一些配置信息写入到该文本文件中,例如数据库相关的配置信息。这也体现了软件设计的一个原则:关注点分离。把代码和配置信息相分离。​......
  • centos7上Hadoop2.7.2完全分布式部署
    1.规划node1         node2           node3datanode       datanode         datanodenamenode     resourcemanager  secondarynamenodenodemanager   nodemanager     no......
  • MassTransit类库Saga文档翻译
    翻译自SagaStateMachinesSagaStateMachines(状态机)SagaStateMachines(状态机)以前被称为Automatonymous,从v8开始被合并到masstrtransit代码库中。介绍Automatonymous是.Net的StateMachines(状态机)类库,它提供了一种C#语法来定义StateMachines,包括状态、事件和行为......
  • centos7.9上hadoop-2.7.2伪分布式部署
    1.安装jdk1.1在Oracle官网上现在jdk1.8,然后上传到Linux服务器中1.2 安装jdk rpm-ivhjdk-8u371-linux-x64.rpm2创建部署用户hadoopuseradd-d/hadoophadoopecho123|passwd--stdinhadoop3修改/etc/hosts4使用Hadoop用户上传hadoop安装包hadoop-2.7......
  • 使用Python实现分布式爬虫
    使用Python实现分布式爬虫在Web爬虫中,分布式爬虫已经成为一种流行的技术,可以帮助我们快速地收集互联网上的数据。下面我们将介绍如何使用Python实现分布式爬虫。什么是分布式爬虫?分布式爬虫是指将爬虫任务分配给多个计算机节点执行,以提高爬取效率和稳定性的一种技术。分布式爬虫通......
  • 分布式事务
    AT:AT模式是一种无侵入的分布式事务解决方案。阿里seata框架,实现了该模式TCC:TCC模式需要用户根据自己的业务场景实现Try、Confirm和Cancel三个操作;事务发起方在一阶段执行Try方式,在二阶段提交执行Confirm方法,二阶段回滚执行Cancel方法。TCC三个方法描述:Try:资源的检测......
  • 分布式机器学习(Parameter Server)
    分布式机器学习中,参数服务器(ParameterServer)用于管理和共享模型参数,其基本思想是将模型参数存储在一个或多个中央服务器上,并通过网络将这些参数共享给参与训练的各个计算节点。每个计算节点可以从参数服务器中获取当前模型参数,并将计算结果返回给参数服务器进行更新。为了保持......