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

上图左侧是正常的事务流程,当执行事务T3时出现异常,则开始反向执行右边的事务补偿,其中C3是T3的补偿,C2是T2的补偿,C1是T1的补偿,将T3,T2,T1已经修改的数据做补偿处理。
实现分析
对Saga事务流程进行排序,当Ti事务完成之后,需要决定下一步要怎么进行。如果成功执行T(i+1)分支,如果失败,则执行C(i-1)分支。这类似一个工作流或是状态机的概念。从实现来看,有两种方式:
集中式实现
集中式协调器负责服务调用以及事务协调(Orchestration)即编排实现:集中式协调器负责服务调用以及事务协调。Saga提供一个控制类,其方便参与者之间的协调工作。事务执行的命令从控制类发起,按照逻辑顺序请求Saga的参与者,从参与者那里接受到反馈以后,控制类在发起向其他参与者的调用。所有Saga的参与者都围绕这个控制类进行沟通和协调工作。

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

实现比对
我个人认为在计算机的世界里没有银弹!任何的解决方案只能说是合适与不合适,而没有完美的契合并解决。
如上两种解决方式都有一定的弊端;对于集中式的实现方式,其弊端如下:
- 必须额外实现一个协调器,相当于增加了系统复杂度
- 需要考虑协调器自身发生故障时应对措施
分布式的实现方式,其弊端如下:
- 添加新的事务步骤时比较麻烦,需要确定哪个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));
流程逻辑:当客户端请求下单服务时,业务逻辑正常执行,执行成功后发布事件到消息队列,状态机监听到对应的订单事件后,修改当前状态,发布事件标识成功或失败,订单服务业务监听事件,响应状态的调整(一般是标识或回滚业务)。

优点
方便简单,而且强大,流程编排能力很强。缺点:引入了rabbitmq,有中间件依赖。
可参考实现:
使用 Masstransit中的 Request/Response 与 Courier 功能实现最终一致性
分布式事务 | 基于MassTransit的StateMachine实现Saga编排式分布式事务
非状态机实现
这一类的实现有eventuate的saga,dtm的saga。
在这一类的实现中,没有引入新的DSL来实现状态机,而是采用函数接口的方式,定义全局事务下的各个分支事务。
优点:
简单易上手,易维护
缺点:
难以做到状态机的事务灵活自定义
ACID与Saga

聊聊分布式解决方案Saga模式的更多相关文章
- 分布式事务 | 使用DTM 的Saga 模式
DTM 简介 前面章节提及的MassTransit.dotnetcore/CAP都提供了分布式事务的处理能力,但也仅局限于Saga和本地消息表模式的实现.那有没有一个独立的分布式事务解决方案,涵盖多种 ...
- 分布式事务 Seata Saga 模式首秀以及三种模式详解 | Meetup#3 回顾
https://mp.weixin.qq.com/s/67NvEVljnU-0-6rb7MWpGw 分布式事务 Seata Saga 模式首秀以及三种模式详解 | Meetup#3 回顾 原创 蚂蚁金 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十九)——分布式事务之Saga模式
在之前的系列文章中聊过分布式事务的一种实现方案,即通过在集群中暴露actor服务来实现分布式事务的本地原子化.但是actor服务本身有其特殊性,场景上并不通用.所以今天来讲讲分布式事务实现方案之sag ...
- 微服务痛点-基于Dubbo + Seata的分布式事务(AT)模式
前言 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案. ...
- 微服务痛点-基于Dubbo + Seata的分布式事务(TCC模式)
前言 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案. ...
- Atitit 全屏模式的cs桌面客户端软件gui h5解决方案 Kiosk模式
Atitit 全屏模式的cs桌面客户端软件gui h5解决方案 Kiosk模式 1.1. Kiosk Software广泛用于公共电脑或者嵌入系统,最常用的就是ATM机.自动服务机之类的系统了.,1 ...
- Solr系列二:solr-部署详解(solr两种部署模式介绍、独立服务器模式详解、SolrCloud分布式集群模式详解)
一.solr两种部署模式介绍 Standalone Server 独立服务器模式:适用于数据规模不大的场景 SolrCloud 分布式集群模式:适用于数据规模大,高可靠.高可用.高并发的场景 二.独 ...
- Spring Cloud Config(一):聊聊分布式配置中心 Spring Cloud Config
目录 Spring Cloud Config(一):聊聊分布式配置中心 Spring Cloud Config Spring Cloud Config(二):基于Git搭建配置中心 Spring Cl ...
- 分布式事务:Saga模式
1 Saga相关概念 1987年普林斯顿大学的Hector Garcia-Molina和Kenneth Salem发表了一篇Paper Sagas,讲述的是如何处理long lived transac ...
- 聊聊分布式下的WebSocket解决方案
前言 最近王子自己搭建了个项目,项目本身很简单,但是里面有使用WebSocket进行消息提醒的功能,大体情况是这样的. 发布消息者在系统中发送消息,实时的把消息推送给对应的一个部门下的所有人. 这里面 ...
随机推荐
- CF1037H Security题解
根据字典序的定义,位置大的大于长度长的,长度长的大于长度短的. 所以我们贪心,先追求长度长的,再追求后面的位置大的,再追求前面的位置大的. 我们要一个能遍历子串的结构,就选 SAM 得了. 还有个限制 ...
- Vue基础语法整理
vue基础用法&基础原理整理 1. vue基础知识和原理 1.1 初识Vue 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象 demo容器里的代码依然符合html规范,只不过混 ...
- java多线程基础小白指南--关键字识别(start,run,sleep,wait,join,yield)
在学习java多线程基础上,会遇到几个关键字,理解并识别它们是掌握多线程的必备知识,下面,我将通过源码或者程序演示给出我对这几个关键字的理解,如果有不同意见,欢迎在评论区或者发私信与我探讨. 一.st ...
- 职场「OKR」,魔幻又内卷
个人习惯称之为[O-KR-KPI]组合: 01 从进厂实习那天开始,就接触了KPI的概念: 互联网公司,年初入职,可能因为那天是周五,又赶上月底,少不了要把KPI搬出来折腾一番: 天时,地利,人和: ...
- ACM-NEFU15届校赛-大一组
A. 三角形面积 #include <bits/stdc++.h> using namespace std; int main() { double a,b,c; double ans,p ...
- PDF打开后显示的名称不是其文件名怎么办?
本文介绍打开PDF文件时,PDF阅读器所显示的文件名称与文件实际名称不一致的解决办法. 就在刚刚准备一篇空间三维建模相关的博客时,偶然发现了如下一个问题: 在打开这个图中名称为空间三维建模 ...
- 5.根据uid获取用户所有收货地址信息和设置默认地址
1.总结:昨天主要是实现了根据uid获取该用户的所有收货地址以及设置默认地址:再对默认地址的实现里面让我认识到它的具体操作,首先我们根据aid查询收货地址 再根据收货地址查询到地址归属人的信息,判断u ...
- Gpssworld仿真(二):并排排队系统模拟
4.3 某一个加油站能够配给三个级别的燃油:①家庭取暖用的燃油:②轻工业用的燃油:③运输用的燃油.每一级别的燃油都有一个对应的油泵.订单中燃油的数量在3000加仑和5000加仑中变化,每次增加10加仑 ...
- SQL concat_ws, collect_set, 和explode合并使用
1. 背景 有一个这样的数据集:字段和字段的值是两列 目的是将这个数据转换成规整的一个特征是一列的数据: 2. 做法 第一步:先造出列 select ucid ,CASE WHEN type ='性别 ...
- Ununtu服务器安装Nginx与PHP
Ununtu服务器安装Nginx与PHP 1. 安装Nginx: 1.1 sudo apt update sudo apt install nginx 验证结果,使用命令: sudo systemct ...