Seata Saga模式详解(底层原理与实现 + Java代码示例(Choreography(编排式))、Orchestration(编制式)))

(一)、 Seata Saga模式详解(底层原理与实现 )

一、Saga模式底层原理详解
1. 核心概念

Saga模式是一种长事务解决方案,它将一个分布式事务拆分为多个本地事务,每个本地事务都有对应的补偿操作。Saga模式有两种实现方式:

  • Choreography(编排式):事件驱动,服务间通过事件通信
  • Orchestration(编制式):中央协调器控制事务流程
2. 三阶段流程详解
  1. 执行阶段

    • 每个服务执行自己的本地事务
    • 成功则提交,失败则触发补偿
  2. 补偿阶段

    • 当某个服务执行失败时,按相反顺序执行之前所有服务的补偿操作
    • 确保系统回到事务开始前的状态
  3. 恢复阶段

    • 处理执行或补偿过程中的异常
    • 可能需要重试或人工干预
3. 底层实现机制
  1. 事务状态管理

    • 每个本地事务都有明确的状态(执行中、已提交、已补偿)
    • 状态持久化到数据库
  2. 补偿操作设计

    • 每个业务操作必须提供对应的补偿操作
    • 补偿操作必须保证幂等性
  3. 异常处理

    • 执行失败时自动触发补偿
    • 补偿失败时可能需要人工干预
  4. 事务传播

    • 通过Saga协调器或事件总线协调多个服务的事务
    • 确保事务的正确流转
二、Saga模式关键点
  1. 补偿操作设计

    • 每个业务操作必须提供对应的补偿操作
    • 补偿操作必须保证幂等性
  2. 事务状态管理

    • 使用状态机管理业务状态
    • 通过状态控制流程走向
  3. 异常处理

    • 执行失败时自动触发补偿
    • 补偿失败时可能需要人工干预
  4. 性能考虑

    • 补偿操作尽量轻量
    • 减少远程调用次数
三、Saga模式适用场景
  1. 适合场景

    • 长时间运行的事务
    • 跨多个服务的业务流程
    • 对最终一致性要求较高的场景
  2. 不适合场景

    • 需要强一致性的场景
    • 简单的数据库事务
    • 对性能要求极高的场景
四、Saga模式最佳实践
  1. 设计原则

    • 每个业务操作必须提供对应的补偿操作
    • 补偿操作必须保证幂等性
    • 尽量减少远程调用次数
  2. 状态管理

    • 使用状态机管理业务状态
    • 通过状态控制流程走向
  3. 异常处理

    • 对每个阶段的方法进行异常捕获
    • 记录详细的日志便于排查问题
  4. 测试验证

    • 编写单元测试验证每个阶段的补偿操作
    • 进行分布式事务的集成测试
    • 测试异常场景(如网络中断、服务宕机)

Saga模式虽然实现复杂度较高,但在需要处理长事务和跨服务业务流程的场景下提供了最大的灵活性,是Seata分布式事务方案中处理复杂业务逻辑的重要模式。

(二)、编排式(Choreography)Saga模式Java完整示例

一、项目结构设计
src/main/java/com/example/saga/
├── event/
│   ├── OrderCreatedEvent.java       # 订单创建事件
│   ├── InventoryReservedEvent.java  # 库存预留成功事件
│   └── PaymentCompletedEvent.java   # 支付完成事件
├── listener/
│   ├── OrderCreatedEventListener.java # 订单创建事件监听器
│   ├── InventoryReservedEventListener.java # 库存预留事件监听器
│   └── PaymentCompletedEventListener.java # 支付完成事件监听器
├── service/
│   ├── OrderService.java              # 订单服务接口
│   ├── InventoryService.java          # 库存服务接口
│   └── PaymentService.java            # 支付服务接口
├── service/impl/
│   ├── OrderServiceImpl.java          # 订单服务实现
│   ├── InventoryServiceImpl.java      # 库存服务实现
│   └── PaymentServiceImpl.java        # 支付服务实现
└── model/
    └── Order.java                     # 订单实体类
二、核心代码实现
1. 业务实体类(Order.java)
package com.example.saga.model;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class Order {
    private Long orderId;
    private Long productId;
    private Integer num;
    private BigDecimal amount;
    private String status; // 订单状态:创建中/已支付/已取消等
    private LocalDateTime createTime;

    // 构造方法、getter和setter省略...
}
2. 事件定义
// OrderCreatedEvent.java
package com.example.saga.event;

import com.example.saga.model.Order;

public class OrderCreatedEvent {
    private Order order;

    public OrderCreatedEvent(Order order) {
        this.order = order;
    }

    public Order getOrder() {
        return order;
    }
}

// InventoryReservedEvent.java
package com.example.saga.event;

import com.example.saga.model.Order;

public class InventoryReservedEvent {
    private Order order;

    public InventoryReservedEvent(Order order) {
        this.order = order;
    }

    public Order getOrder() {
        return order;
    }
}

// PaymentCompletedEvent.java
package com.example.saga.event;

import com.example.saga.model.Order;

public class PaymentCompletedEvent {
    private Order order;

    public PaymentCompletedEvent(Order order) {
        this.order = order;
    }

    public Order getOrder() {
        return order;
    }
}
3. 服务接口定义
// OrderService.java
package com.example.saga.service;

import com.example.saga.model.Order;

public interface OrderService {
    boolean createOrder(Order order);          // 创建订单
    void compensateCreateOrder(Order order);   // 补偿创建订单
}

// InventoryService.java
package com.example.saga.service;

import com.example.saga.model.Order;

public interface InventoryService {
    boolean reduceStock(Long productId, Integer num);      // 减少库存
    void compensateReduceStock(Long productId, Integer num); // 补偿减少库存
}

// PaymentService.java
package com.example.saga.service;

import com.example.saga.model.Order;

public interface PaymentService {
    boolean pay(Long orderId, BigDecimal amount);      // 支付
    void compensatePay(Long orderId, BigDecimal amount); // 补偿支付
}
4. 服务实现类
// OrderServiceImpl.java
package com.example.saga.service.impl;

import com.example.saga.model.Order;
import com.example.saga.service.OrderService;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements OrderService {
    
    @Override
    public boolean createOrder(Order order) {
        // 实际项目中这里会调用DAO层保存订单
        System.out.println("创建订单: " + order.getOrderId());
        order.setStatus("创建中");
        return true; // 模拟成功
    }
    
    @Override
    public void compensateCreateOrder(Order order) {
        // 实际项目中这里会调用DAO层更新订单状态
        System.out.println("补偿创建订单: " + order.getOrderId());
        order.setStatus("已取消");
    }
}

// InventoryServiceImpl.java
package com.example.saga.service.impl;

import com.example.saga.model.Order;
import com.example.saga.service.InventoryService;
import org.springframework.stereotype.Service;

@Service
public class InventoryServiceImpl implements InventoryService {
    
    @Override
    public boolean reduceStock(Long productId, Integer num) {
        // 实际项目中这里会调用DAO层减少库存
        System.out.println("减少库存: 商品ID=" + productId + ", 数量=" + num);
        return true; // 模拟成功
    }
    
    @Override
    public void compensateReduceStock(Long productId, Integer num) {
        // 实际项目中这里会调用DAO层恢复库存
        System.out.println("补偿减少库存: 商品ID=" + productId + ", 数量=" + num);
    }
}

// PaymentServiceImpl.java
package com.example.saga.service.impl;

import com.example.saga.model.Order;
import com.example.saga.service.PaymentService;
import org.springframework.stereotype.Service;

@Service
public class PaymentServiceImpl implements PaymentService {
    
    @Override
    public boolean pay(Long orderId, BigDecimal amount) {
        // 实际项目中这里会调用支付接口
        System.out.println("支付订单: " + orderId + ", 金额=" + amount);
        return true; // 模拟成功
    }
    
    @Override
    public void compensatePay(Long orderId, BigDecimal amount) {
        // 实际项目中这里会调用支付接口退款
        System.out.println("补偿支付: 订单=" + orderId + ", 金额=" + amount);
    }
}
5. 事件监听器实现
// OrderCreatedEventListener.java
package com.example.saga.listener;

import com.example.saga.event.OrderCreatedEvent;
import com.example.saga.service.InventoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class OrderCreatedEventListener {

    @Autowired
    private InventoryService inventoryService;

    @EventListener
    public void handleOrderCreatedEvent(OrderCreatedEvent event) {
        System.out.println("收到订单创建事件,准备预留库存...");
        boolean result = inventoryService.reduceStock(event.getOrder().getProductId(), event.getOrder().getNum());
        if (result) {
            // 发布库存预留成功事件
            System.out.println("库存预留成功,发布库存预留事件");
            // 实际项目中这里会发布事件,这里简化处理
        } else {
            // 库存预留失败,发布补偿事件
            System.out.println("库存预留失败,发布补偿事件");
            // 实际项目中这里会发布补偿事件
        }
    }
}

// InventoryReservedEventListener.java
package com.example.saga.listener;

import com.example.saga.event.InventoryReservedEvent;
import com.example.saga.service.PaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class InventoryReservedEventListener {

    @Autowired
    private PaymentService paymentService;

    @EventListener
    public void handleInventoryReservedEvent(InventoryReservedEvent event) {
        System.out.println("收到库存预留成功事件,准备支付...");
        boolean result = paymentService.pay(event.getOrder().getOrderId(), event.getOrder().getAmount());
        if (result) {
            // 发布支付完成事件
            System.out.println("支付完成,发布支付完成事件");
            // 实际项目中这里会发布事件
        } else {
            // 支付失败,发布补偿事件
            System.out.println("支付失败,发布补偿事件");
            // 实际项目中这里会发布补偿事件
        }
    }
}

// PaymentCompletedEventListener.java
package com.example.saga.listener;

import com.example.saga.event.PaymentCompletedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class PaymentCompletedEventListener {

    @EventListener
    public void handlePaymentCompletedEvent(PaymentCompletedEvent event) {
        System.out.println("收到支付完成事件,Saga事务执行成功");
        // 实际项目中这里会更新订单状态为已完成
    }
}
6. 编排器核心实现(简化版)
package com.example.saga.orchestrator;

import com.example.saga.model.Order;
import com.example.saga.service.OrderService;
import com.example.saga.event.OrderCreatedEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
public class OrderSagaOrchestrator {

    @Autowired
    private OrderService orderService;
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 执行Saga事务编排(简化版)
     * @param order 订单对象
     */
    public void executeOrderSaga(Order order) {
        try {
            // 1. 执行订单创建
            boolean orderResult = orderService.createOrder(order);
            if (!orderResult) {
                System.out.println("订单创建失败,Saga终止");
                return;
            }
            
            // 2. 发布订单创建事件
            System.out.println("发布订单创建事件");
            eventPublisher.publishEvent(new OrderCreatedEvent(order));
            
            // 实际项目中这里会等待事件处理完成,这里简化处理
            
        } catch (Exception e) {
            System.out.println("Saga执行异常: " + e.getMessage());
            // 异常处理逻辑
        }
    }
}
三、测试类示例
package com.example.saga;

import com.example.saga.model.Order;
import com.example.saga.orchestrator.OrderSagaOrchestrator;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;

@SpringBootTest
public class SagaTest {

    @Autowired
    private OrderSagaOrchestrator orderSagaOrchestrator;

    @Test
    public void testOrderSaga() {
        Order order = new Order();
        order.setOrderId(1L);
        order.setProductId(1001L);
        order.setNum(2);
        order.setAmount(new BigDecimal("100.00"));
        
        // 执行Saga事务
        orderSagaOrchestrator.executeOrderSaga(order);
    }
}
四、关键设计要点
  1. 事件驱动机制

    • 通过事件通知协调各个服务的事务步骤
    • 每个服务只关注自己的业务逻辑和事件处理
  2. 补偿机制

    • 每个正向操作必须有对应的补偿操作
    • 补偿操作必须保证幂等性
    • 补偿按相反顺序执行(通过事件机制隐式实现)
  3. 异常处理

    • 捕获所有可能的异常
    • 记录详细的错误日志
    • 根据业务需求决定是否重试
  4. 扩展性考虑

    • 可以通过配置文件定义事务步骤
    • 支持动态添加/删除事务步骤
    • 支持事务步骤的重试策略
五、实际项目改进建议
  1. 事件持久化

    • 将事件持久化到数据库或消息队列
    • 支持事件重放和事务恢复
  2. 分布式协调

    • 在微服务架构中,可以使用消息队列(如Kafka、RabbitMQ)协调多个服务的事务
    • 实现Saga的分布式执行
  3. 监控和告警

    • 监控Saga事务的执行状态
    • 对长时间未完成的事务进行告警
  4. 日志记录

    • 记录详细的执行日志和补偿日志
    • 支持事务审计和排查问题

这个示例展示了编排式(Choreography)Saga模式的核心实现方式,实际项目中可以根据具体需求进行扩展和优化。

(三) Orchestration(编制式)Saga模式Java完整示例

一、项目结构设计
src/main/java/com/example/saga/
├── orchestrator/
│   └── OrderSagaOrchestrator.java       # 编排器核心类
├── service/
│   ├── OrderService.java                # 订单服务接口
│   ├── InventoryService.java            # 库存服务接口
│   └── PaymentService.java              # 支付服务接口
├── service/impl/
│   ├── OrderServiceImpl.java            # 订单服务实现
│   ├── InventoryServiceImpl.java        # 库存服务实现
│   └── PaymentServiceImpl.java          # 支付服务实现
└── model/
    └── Order.java                       # 订单实体类
二、核心代码实现
1. 业务实体类(Order.java)
package com.example.saga.model;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class Order {
    private Long orderId;
    private Long productId;
    private Integer num;
    private BigDecimal amount;
    private String status; // 订单状态:创建中/已支付/已取消等
    private LocalDateTime createTime;

    // 构造方法、getter和setter省略...
}
2. 服务接口定义
// OrderService.java
package com.example.saga.service;

import com.example.saga.model.Order;

public interface OrderService {
    boolean createOrder(Order order);          // 创建订单
    void compensateCreateOrder(Order order);   // 补偿创建订单
}

// InventoryService.java
package com.example.saga.service;

import com.example.saga.model.Order;

public interface InventoryService {
    boolean reduceStock(Long productId, Integer num);      // 减少库存
    void compensateReduceStock(Long productId, Integer num); // 补偿减少库存
}

// PaymentService.java
package com.example.saga.service;

import com.example.saga.model.Order;

public interface PaymentService {
    boolean pay(Long orderId, BigDecimal amount);      // 支付
    void compensatePay(Long orderId, BigDecimal amount); // 补偿支付
}
3. 服务实现类
// OrderServiceImpl.java
package com.example.saga.service.impl;

import com.example.saga.model.Order;
import com.example.saga.service.OrderService;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements OrderService {
    
    @Override
    public boolean createOrder(Order order) {
        // 实际项目中这里会调用DAO层保存订单
        System.out.println("创建订单: " + order.getOrderId());
        order.setStatus("创建中");
        return true; // 模拟成功
    }
    
    @Override
    public void compensateCreateOrder(Order order) {
        // 实际项目中这里会调用DAO层更新订单状态
        System.out.println("补偿创建订单: " + order.getOrderId());
        order.setStatus("已取消");
    }
}

// InventoryServiceImpl.java
package com.example.saga.service.impl;

import com.example.saga.model.Order;
import com.example.saga.service.InventoryService;
import org.springframework.stereotype.Service;

@Service
public class InventoryServiceImpl implements InventoryService {
    
    @Override
    public boolean reduceStock(Long productId, Integer num) {
        // 实际项目中这里会调用DAO层减少库存
        System.out.println("减少库存: 商品ID=" + productId + ", 数量=" + num);
        return true; // 模拟成功
    }
    
    @Override
    public void compensateReduceStock(Long productId, Integer num) {
        // 实际项目中这里会调用DAO层恢复库存
        System.out.println("补偿减少库存: 商品ID=" + productId + ", 数量=" + num);
    }
}

// PaymentServiceImpl.java
package com.example.saga.service.impl;

import com.example.saga.model.Order;
import com.example.saga.service.PaymentService;
import org.springframework.stereotype.Service;

@Service
public class PaymentServiceImpl implements PaymentService {
    
    @Override
    public boolean pay(Long orderId, BigDecimal amount) {
        // 实际项目中这里会调用支付接口
        System.out.println("支付订单: " + orderId + ", 金额=" + amount);
        return true; // 模拟成功
    }
    
    @Override
    public void compensatePay(Long orderId, BigDecimal amount) {
        // 实际项目中这里会调用支付接口退款
        System.out.println("补偿支付: 订单=" + orderId + ", 金额=" + amount);
    }
}
4. 编排器核心实现(OrderSagaOrchestrator.java)
package com.example.saga.orchestrator;

import com.example.saga.model.Order;
import com.example.saga.service.InventoryService;
import com.example.saga.service.OrderService;
import com.example.saga.service.PaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderSagaOrchestrator {

    @Autowired
    private OrderService orderService;
    
    @Autowired
    private InventoryService inventoryService;
    
    @Autowired
    private PaymentService paymentService;

    /**
     * 执行Saga事务编排
     * @param order 订单对象
     */
    public void executeOrderSaga(Order order) {
        try {
            // 1. 执行订单创建
            boolean orderResult = orderService.createOrder(order);
            if (!orderResult) {
                System.out.println("订单创建失败,Saga终止");
                return;
            }
            
            // 2. 执行库存减少
            boolean inventoryResult = inventoryService.reduceStock(order.getProductId(), order.getNum());
            if (!inventoryResult) {
                System.out.println("库存减少失败,执行补偿");
                orderService.compensateCreateOrder(order);
                return;
            }
            
            // 3. 执行支付
            boolean paymentResult = paymentService.pay(order.getOrderId(), order.getAmount());
            if (!paymentResult) {
                System.out.println("支付失败,执行补偿");
                inventoryService.compensateReduceStock(order.getProductId(), order.getNum());
                orderService.compensateCreateOrder(order);
                return;
            }
            
            System.out.println("Saga事务执行成功");
            
        } catch (Exception e) {
            System.out.println("Saga执行异常: " + e.getMessage());
            // 异常处理逻辑(可根据需要扩展)
        }
    }
}
三、测试类示例
package com.example.saga;

import com.example.saga.model.Order;
import com.example.saga.orchestrator.OrderSagaOrchestrator;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;

@SpringBootTest
public class SagaTest {

    @Autowired
    private OrderSagaOrchestrator orderSagaOrchestrator;

    @Test
    public void testOrderSaga() {
        Order order = new Order();
        order.setOrderId(1L);
        order.setProductId(1001L);
        order.setNum(2);
        order.setAmount(new BigDecimal("100.00"));
        
        // 执行Saga事务
        orderSagaOrchestrator.executeOrderSaga(order);
    }
}
四、关键设计要点
  1. 编排器职责

    • 控制事务执行顺序
    • 处理异常和补偿逻辑
    • 维护事务状态
  2. 补偿机制

    • 每个正向操作必须有对应的补偿操作
    • 补偿操作必须保证幂等性
    • 补偿按相反顺序执行
  3. 异常处理

    • 捕获所有可能的异常
    • 记录详细的错误日志
    • 根据业务需求决定是否重试
  4. 扩展性考虑

    • 可以通过配置文件定义事务步骤
    • 支持动态添加/删除事务步骤
    • 支持事务步骤的重试策略
五、实际项目改进建议
  1. 状态持久化

    • 将事务状态持久化到数据库
    • 支持事务恢复和重试
  2. 分布式协调

    • 在微服务架构中,可以使用消息队列协调多个服务的事务
    • 实现Saga的分布式执行
  3. 监控和告警

    • 监控Saga事务的执行状态
    • 对长时间未完成的事务进行告警
  4. 日志记录

    • 记录详细的执行日志和补偿日志
    • 支持事务审计和排查问题

这个示例展示了Orchestration(编制式)Saga模式的核心实现方式,实际项目中可以根据具体需求进行扩展和优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值