当前位置: 首页 > news >正文

编排式 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. 系统流程

  1. Order Service:接收创建订单请求,调用 Saga Orchestrator Service 开始 Saga 流程。
  2. Saga Orchestrator:协调 Inventory Service 扣减库存,等到确认成功后,继续后续操作(如创建订单)。
  3. Inventory Service:接收扣减库存请求,执行库存扣减,如果成功,通知 Saga Orchestrator。如果失败,则触发补偿操作。
  4. 补偿操作:如果任何一个服务的事务失败,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 进行服务间的消息通信,可以将系统解耦,提高扩展性。在这种模式下,协调者充当了服务之间的桥梁,负责事务流的管理,并在必要时执行补偿操作。


http://www.mrgr.cn/news/82943.html

相关文章:

  • arr.length 和 string.length()
  • Transformer 和 Attention机制入门
  • Element-plus表单总结
  • Lua协同程序(线程)
  • Kubernetes Gateway API-4-TCPRoute和GRPCRoute
  • 66.加一 python
  • 通过gradle发布aar或jar携带sources-jar到maven nexus
  • 【简博士统计学习方法】第1章:7. 生成模型与判别模型
  • HarmonyOS开发:粒子动画应用实战
  • TCP 套接字 方法
  • 我在广州学 Mysql 系列——与索引相关的练习题
  • 前端 动图方案
  • C#—Task异步的常用方法及TaskFactory工厂类详解
  • ELK实战(最详细)
  • cuda实现flash_attn_mma_share_kv源码分析
  • 用VS C#构建Windows服务【纯操作版,附带项目地址】
  • [开源]自动化定位建图系统
  • A/B实验之置信检验(一):如何避免误判 (I类) 和漏报 (II类)
  • 137. 只出现一次的数字 II
  • 【Rust自学】10.8. 生命周期 Pt.4:方法定义中的生命周期标注与静态生命周期
  • 9. C 语言 循环控制结构详解
  • 数据传送类指令
  • 【Linux】上传、下载、压缩、解压
  • Python 模拟登录网页,或者编写爬虫时模拟登录的详细总结
  • 【Rust自学】10.7. 生命周期 Pt.3:输入输出生命周期与3规则
  • 30天开发操作系统 第 12 天 -- 定时器