编排式 Saga 模式
编排式 Saga 模式(Orchestrated Saga)是指由一个中央协调者(Orchestrator)控制多个服务间的事务执行。与协作式 Saga 模式不同,编排式 Saga 模式不依赖于事件驱动,而是通过协调者来控制整个 Saga 流程的执行。协调者负责调用各个参与服务,确保每个子事务按顺序执行,并在某个子事务失败时触发补偿操作。
编排式 Saga 模式实现步骤
我们将实现一个基于编排式 Saga 模式的跨服务数据保存方案,使用 Spring Boot 来开发微服务,使用 RabbitMQ 或 Kafka 作为消息队列进行通信,并通过一个中央协调者来管理整个 Saga 流程。
以下是如何使用编排式 Saga 模式来实现一个典型的跨服务操作:订单创建和库存扣减。
1. 架构设计
我们有两个微服务:
- Order Service:负责创建订单。
- Inventory Service:负责管理库存。
- Saga Orchestrator Service:协调整个 Saga 流程,包括执行各服务事务并在失败时触发补偿操作。
2. 技术栈
- Spring Boot:用于开发微服务。
- Spring Cloud:用于服务注册、发现和治理。
- Spring AMQP / Kafka:用于服务间消息传递(可选择 RabbitMQ 或 Kafka)。
- Spring Data JPA:用于数据库操作。
- Transactional Outbox Pattern:用来确保跨服务操作的一致性。
3. 系统流程
- Order Service:接收创建订单请求,调用 Saga Orchestrator Service 开始 Saga 流程。
- Saga Orchestrator:协调 Inventory Service 扣减库存,等到确认成功后,继续后续操作(如创建订单)。
- Inventory Service:接收扣减库存请求,执行库存扣减,如果成功,通知 Saga Orchestrator。如果失败,则触发补偿操作。
- 补偿操作:如果任何一个服务的事务失败,Saga Orchestrator 会调用补偿操作回滚之前的事务,确保最终一致性。
4. Spring Boot 示例实现
4.1 创建 Order Service
Order Service 负责处理订单请求,并与 Saga Orchestrator 配合,触发 Saga 流程。
// OrderService.java
@Service
public class OrderService {@Autowiredprivate SagaOrchestrator sagaOrchestrator;// 创建订单@Transactionalpublic void createOrder(Order order) {// Step 1: 创建订单orderRepository.save(order);// Step 2: 调用 Saga Orchestrator 开始整个流程sagaOrchestrator.startSaga(order);}
}
4.2 创建 Saga Orchestrator Service
Saga Orchestrator Service 是整个 Saga 模式的核心,它负责协调各个服务之间的事务执行。首先,它会启动 Saga 事务,接着协调 Inventory Service 执行库存扣减操作,并处理补偿操作。
// SagaOrchestrator.java
@Service
public class SagaOrchestrator {@Autowiredprivate InventoryService inventoryService;@Autowiredprivate OrderRepository orderRepository;// 启动 Saga 流程@Transactionalpublic void startSaga(Order order) {try {// Step 1: 调用库存服务扣减库存boolean inventorySuccess = inventoryService.decreaseInventory(order.getItemId(), order.getQuantity());if (!inventorySuccess) {throw new Exception("Inventory insufficient");}// Step 2: 库存扣减成功后,继续创建订单order.setStatus("Created");orderRepository.save(order);} catch (Exception e) {// Step 3: 如果出错,执行补偿操作compensate(order);}}// 补偿方法,回滚库存操作private void compensate(Order order) {// 回滚库存,增加库存inventoryService.rollbackInventory(order.getItemId(), order.getQuantity());// 回滚订单,设置订单为失败状态order.setStatus("Failed");orderRepository.save(order);}
}
4.3 创建 Inventory Service
Inventory Service 负责扣减库存并通知 Saga Orchestrator 执行后续操作。
// InventoryService.java
@Service
public class InventoryService {@Autowiredprivate InventoryRepository inventoryRepository;// 扣减库存@Transactionalpublic boolean decreaseInventory(Long itemId, int quantity) {Inventory inventory = inventoryRepository.findByItemId(itemId);if (inventory.getStock() < quantity) {return false; // 库存不足}inventory.setStock(inventory.getStock() - quantity);inventoryRepository.save(inventory);return true; // 库存扣减成功}// 补偿操作,回滚库存@Transactionalpublic void rollbackInventory(Long itemId, int quantity) {Inventory inventory = inventoryRepository.findByItemId(itemId);inventory.setStock(inventory.getStock() + quantity); // 恢复库存inventoryRepository.save(inventory);}
}
4.4 消息队列(RabbitMQ 或 Kafka)集成
为了实现 Saga 模式的跨服务通信,我们可以使用消息队列来传递消息。这里我们使用 RabbitMQ 作为消息队列。
在 application.properties 中配置 RabbitMQ:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
在 SagaOrchestrator 和 InventoryService 中,我们可以通过 RabbitTemplate 来发送和接收消息。
// SagaOrchestrator.java
@Autowired
private RabbitTemplate rabbitTemplate;// 启动 Saga 流程时,发送事件
public void startSaga(Order order) {// 发送一个消息,通知库存服务处理库存rabbitTemplate.convertAndSend("inventoryExchange", "inventory.decrease", order);
}// 监听库存扣减消息的回调
@RabbitListener(queues = "inventory.decrease.queue")
public void handleInventoryDecrease(Order order) {try {// 扣减库存并继续订单处理boolean inventorySuccess = inventoryService.decreaseInventory(order.getItemId(), order.getQuantity());if (!inventorySuccess) {throw new Exception("Inventory insufficient");}// 订单处理继续order.setStatus("Created");orderRepository.save(order);} catch (Exception e) {// 执行补偿操作compensate(order);}
}
4.5 设置消息队列的交换机和队列
@Configuration
public class RabbitMQConfig {@Beanpublic TopicExchange inventoryExchange() {return new TopicExchange("inventoryExchange");}@Beanpublic Queue inventoryDecreaseQueue() {return new Queue("inventory.decrease.queue");}@Beanpublic Binding inventoryDecreaseBinding() {return BindingBuilder.bind(inventoryDecreaseQueue()).to(inventoryExchange()).with("inventory.decrease");}@Beanpublic Jackson2JsonMessageConverter jackson2JsonMessageConverter() {return new Jackson2JsonMessageConverter();}@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory,Jackson2JsonMessageConverter jackson2JsonMessageConverter) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter);return rabbitTemplate;}
}
5. 确保最终一致性
在编排式 Saga 模式中,每个服务通过本地事务来保证操作的原子性,并通过协调者来确保每个子事务执行成功。当某个服务失败时,协调者会触发补偿操作回滚之前的操作。关键要素是:
补偿操作:服务必须提供回滚或补偿机制,确保在失败时能够撤销已完成的事务。
幂等性:补偿操作应该是幂等的,确保多次执行不会产生不一致的结果。
6. 总结
编排式 Saga 模式通过中央协调者来管理跨服务事务,确保最终一致性和数据可靠性。使用 RabbitMQ 或 Kafka 进行服务间的消息通信,可以将系统解耦,提高扩展性。在这种模式下,协调者充当了服务之间的桥梁,负责事务流的管理,并在必要时执行补偿操作。
相关文章:
编排式 Saga 模式
编排式 Saga 模式(Orchestrated Saga)是指由一个中央协调者(Orchestrator)控制多个服务间的事务执行。与协作式 Saga 模式不同,编排式 Saga 模式不依赖于事件驱动,而是通过协调者来控制整个 Saga 流程的执行…...
QT 下拉菜单设置参数 起始端口/结束端口/线程数量 端口扫描4
上篇文章QT实现 端口扫描暂停和继续功能 3-CSDN博客 双击 添加对话框类 界面设计 由于主体代码已经写完,只需要更改参数的获取即可 获取起始端口结束端口的输入 槽函数 给主界面类添加调用对话框类的功能 实现功能:点击菜单项可以弹出对话框窗体 增加槽…...
缓存-Redis-常见问题-缓存击穿-永不过期+逻辑过期(全面 易理解)
缓存击穿(Cache Breakdown) 是在高并发场景下,当某个热点数据在缓存中失效或不存在时,瞬间大量请求同时击中数据库,导致数据库压力骤增甚至崩溃的现象。为了解决这一问题,“永不过期” “逻辑过期” 的策略…...
137. 只出现一次的数字 II
137. 只出现一次的数字 II 题目-中等难度1. 位运算2. 位运算 题目-中等难度 给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法且使用常数…...
【力扣热题100】—— Day18.将有序数组转换为二叉搜索树
期末考试完毕,假期学习开始! —— 25.1.7 108. 将有序数组转换为二叉搜索树 给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵平衡二叉搜索树。 示例 1: 输入:nums [-10,-3,0,5,9] …...
PyTorch 官方文档 中文版本
文档来源 https://pytorch.cadn.net.cn 大多数机器学习工作流都涉及处理数据、创建模型、优化模型 参数,并保存经过训练的模型。本教程向您介绍完整的 ML 工作流 在 PyTorch 中实现,并提供了用于了解有关每个概念的更多信息的链接。 我们将使用 Fashion…...
电力智能问答RAG: 多问题生成、思维链提示生成;混合编码和重排序策略
电力智能问答RAG 目录 电力智能问答RAG文档转换、元信息抽取与增强及文档解析模块多问题生成、思维链提示生成和指令微调数据集构建模块混合编码和重排序策略文档转换、元信息抽取与增强及文档解析模块 在电力领域的知识处理中,文档转换、元信息抽取与增强及文档解析模块发挥…...
C#高级:递归4-根据一颗树递归生成数据列表
一、目的 该程序展示了如何将树形结构的数据(例如家庭成员信息)转化为一维列表形式,以便于存储、展示或操作。 二、流程思路 创建树:首先通过 GetDemoTree 创建一个简单的家庭树,树的根节点是“爸爸”,然…...
PDFelement 特别版
Wondershare PDFelement Pro 是一款非常强大的PDF编辑软件,它允许用户轻松地编辑、转换、创建和管理PDF文件。这个中文特别版的软件具有许多令人印象深刻的功能,PDFelement Pro 提供了丰富的编辑功能,可以帮助用户直接在PDF文件中添加、删除、…...
云计算在医疗行业的应用
云计算在医疗行业的应用广泛而深入,为医疗服务带来了前所未有的变革。以下是对云计算在医疗行业应用的详细解析: ### 一、医疗数据共享与整合 云计算平台具有强大的数据存储和处理能力,使得医疗数据共享与整合成为可能。通过云计算平台&…...
(转)rabbitmq怎么保证消息不丢失?
RabbitMQ 可以通过以下多种机制来保证消息不丢失: 生产阶段 - 持久化队列和交换器: - 在声明队列和交换器时,将 durable 参数设置为 true ,确保它们是持久化的。这样,即使 RabbitMQ 节点重新启动,队列和交…...
每日一题:链表中环的入口结点
文章目录 判断链表环的入口节点描述数据范围:复杂度要求:输入输出 示例代码实现思路解析注意事项: 判断链表环的入口节点 描述 给定一个链表,判断该链表是否存在环。如果存在环,返回环的入口节点;如果不存…...
k8s里面etcd的作用
etcd 是 Kubernetes 集群中一个至关重要的组件,它是一个开源的分布式键值存储系统,主要用于存储和管理 Kubernetes 集群的配置和状态信息。以下是 etcd 在 Kubernetes 中的具体作用和功能: ### 1. **集群状态存储** etcd 是 Kubernetes 集群的持久化存储后端,负责存储和管…...
使用 uniapp 开发微信小程序遇到的坑
0. 每次修改代码时,都会触发微信开发工具重新编译 终极大坑,暂未找到解决方案 1. input 无法聚焦问题 问题:在小程序开发工具中,input 会突然无法聚焦,重启也不行。但是真机调试可以正常聚焦。 解决办法:…...
AlphaPi相关硬件驱动提取
初涉硬件编程,在咸鱼上搞了几块AlphaPi和microbit的板鼓捣了一下,alphapi生态不完善,网上又无任何文档,搞封闭,可玩性实在有限,但貌似相关扩展板是可以插microbit的,于是想把这些扩展版用microb…...
【学习笔记】数据结构(十)
内部排序 文章目录 内部排序10.1 概述10.2 插入排序10.2.1 直接插入排序10.2.2 其他插入排序10.2.2.1 折半插入排序(Binary Insertion Sort)10.2.2.2 2-路插入排序(Two-Way Insertion Sort)10.2.2.3 表插入排序(Table Insertion Sort…...
Unity中 Xlua使用整理(二)
1.Xlua的配置应用 xLua所有的配置都支持三种方式:打标签;静态列表;动态列表。配置要求: 列表方式均必须是static的字段/属性 列表方式均必须放到一个static类 建议不用标签方式 建议列表方式配置放Editor目录(如果是H…...
刚体变换矩阵的逆
刚体运动中的变换矩阵为: 求得变换矩阵的逆矩阵为: opencv应用 cv::Mat R; cv::Mat t;R.t(), -R.t()*t...
高等数学-----极限、函数、连续
考研数学笔记...
ubuntu 创建服务、查看服务日志
1. 在 /etc/systemd/system/ 下创建文件,名称为 xxx.service [Unit] DescriptionYour Service Description Afternetwork.target[Service] Typesimple ExecStart/path/to/your/service/executable Restarton-failure[Install] WantedBymulti-user.target2. 配置服务…...
网络协议分析AI应用:使用PyTorch进行加密流量分类与异常检测
网络协议分析AI应用:使用PyTorch进行加密流量分类与异常检测 1. 网络安全的新挑战与AI解决方案 现代网络环境中,加密流量占比已超过80%,传统基于规则和签名的检测方法面临严峻挑战。想象一下,网络安全工程师每天需要分析数百万个…...
如何用开源工具永久保存微信聊天记录:5个实用技巧让珍贵对话永不丢失
如何用开源工具永久保存微信聊天记录:5个实用技巧让珍贵对话永不丢失 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Tre…...
CFD Vision 2030:解码计算流体动力学的未来革命路径(技术解析篇)
1. CFD Vision 2030的核心挑战与现状 计算流体动力学(CFD)在航空航天领域已经彻底改变了传统设计流程。十年前那份具有里程碑意义的报告《CFD Vision 2030》描绘了一个令人振奋的技术蓝图,但当我们站在2024年回望时,发现现实进展与…...
WPF SaveFileDialog高级功能实战:从基础配置到自定义扩展
1. SaveFileDialog基础配置与核心功能 刚接触WPF开发时,我发现SaveFileDialog这个控件就像个智能文件保存助手。它不仅能帮用户选择保存位置,还能处理各种文件操作细节。先来看看最基础的用法,这里我结合自己踩过的坑给大家分享几个实用技巧。…...
我试了四种去除 Gemini 水印的方法,整理成一篇实用对比野
认识Pass层级结构 Pass范围从上到下一共分为5个层级: 模块层级:单个.ll或.bc文件 调用图层级:函数调用的关系。 函数层级:单个函数。 基本块层级:单个代码块。例如C语言中{}括起来的最小代码。 指令层级:单…...
我不是在用 AI 助手,我在把自己的能力沉淀成组织资产暗
1. 什么是 Apache SeaTunnel? Apache SeaTunnel 是一个非常易于使用、高性能、支持实时流式和离线批处理的海量数据集成平台。它的目标是解决常见的数据集成问题,如数据源多样性、同步场景复杂性以及资源消耗高的问题。 核心特性 丰富的数据源支持&#…...
3分钟极速上手:网盘下载加速神器全功能使用指南
3分钟极速上手:网盘下载加速神器全功能使用指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 /…...
重新定义桌面美学:掌握TranslucentTB的3个颠覆性任务栏定制方案
重新定义桌面美学:掌握TranslucentTB的3个颠覆性任务栏定制方案 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB 想象一下&…...
解决AI人像风格不稳定:造相-Z-Image-Turbo亚洲美女LoRA实战体验
解决AI人像风格不稳定:造相-Z-Image-Turbo亚洲美女LoRA实战体验 1. 为什么需要LoRA技术? 在AI图像生成领域,风格一致性一直是困扰开发者和用户的难题。传统模型生成的人像往往存在以下问题: 风格漂移:同一组提示词在…...
深度解析:ComfyUI-Manager节点冲突检测的5种技术解决方案与架构设计
深度解析:ComfyUI-Manager节点冲突检测的5种技术解决方案与架构设计 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable …...
