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

编排式 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 {

    @Autowired
    private SagaOrchestrator sagaOrchestrator;

    // 创建订单
    @Transactional
    public 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 {

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private OrderRepository orderRepository;

    // 启动 Saga 流程
    @Transactional
    public 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 {

    @Autowired
    private InventoryRepository inventoryRepository;

    // 扣减库存
    @Transactional
    public 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; // 库存扣减成功
    }

    // 补偿操作,回滚库存
    @Transactional
    public 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 {

    @Bean
    public TopicExchange inventoryExchange() {
        return new TopicExchange("inventoryExchange");
    }

    @Bean
    public Queue inventoryDecreaseQueue() {
        return new Queue("inventory.decrease.queue");
    }

    @Bean
    public Binding inventoryDecreaseBinding() {
        return BindingBuilder.bind(inventoryDecreaseQueue()).to(inventoryExchange()).with("inventory.decrease");
    }
}

5. 确保最终一致性

在编排式 Saga 模式中,每个服务通过本地事务来保证操作的原子性,并通过协调者来确保每个子事务执行成功。当某个服务失败时,协调者会触发补偿操作回滚之前的操作。关键要素是:

补偿操作:服务必须提供回滚或补偿机制,确保在失败时能够撤销已完成的事务。
幂等性:补偿操作应该是幂等的,确保多次执行不会产生不一致的结果。

6. 总结

编排式 Saga 模式通过中央协调者来管理跨服务事务,确保最终一致性和数据可靠性。使用 RabbitMQ 或 Kafka 进行服务间的消息通信,可以将系统解耦,提高扩展性。在这种模式下,协调者充当了服务之间的桥梁,负责事务流的管理,并在必要时执行补偿操作。


http://www.kler.cn/a/471211.html

相关文章:

  • 【竞技宝】CS2:HLTV2024职业选手排名TOP8-broky
  • 重温设计模式--13、策略模式
  • 免费一键图片转3D模型,AI建模,一键把图片转三维模型,二维图片转3维模型,AI建模
  • Mysql--基础篇--数据类型(整数,浮点数,日期,枚举,二进制,空间类型等)
  • centOS7
  • 【游戏设计原理】53 - 解决问题的障碍
  • WLAN基本原理与配置
  • C++ 数据结构与算法——寻找最大素数因子的整数
  • FPGA实现UART对应的电路和单片机内部配合寄存器实现的电路到底有何区别?
  • Hadoop解决数据倾斜方法
  • git版本管理
  • 电力领域检索增强生成框架
  • 2025最新版Python 3.13.1安装使用指南
  • linux音视频采集技术: v4l2
  • Oracle Dataguard(主库为 RAC 双节点集群)配置详解(1):安装 Oracle11g RAC 双节点集群
  • 在DVWA靶机从渗透到控制(weevely和中国蚁剑)
  • Taro地图组件和小程序定位
  • 十五、Vue 响应接口
  • [大模型开源]SecGPT 网络安全大模型
  • java调用外部API,通过http请求,HttpGet和HttpPost方式实现
  • Elixir语言的正则表达式
  • HDFS异构存储和存储策略
  • 51单片机——步进电机模块
  • 使用 SAML 2.0协议需要注意的安全问题
  • .net core 线程锁,互斥锁,自旋锁,混合锁
  • shell-条件判断