在微服务中使用 Spring Boot 和 ActiveMQ 实现Saga模式

微服务彻底改变了我们构建和部署软件应用程序的方式,为系统的不同部分提供了可扩展性、灵活性和独立性。然而,在微服务架构中管理分布式事务可能具有挑战性。这就是 Saga 模式发挥作用的地方。在本文中,我们将探讨 Saga 模式,并提供使用 Spring Boot 和 ActiveMQ 实现该模式的示例。

理解 Saga 模式

Saga 模式是一种用于管理微服务架构中的分布式事务的设计模式。它解决了跨多个微服务维护数据一致性的复杂性和挑战,同时避免了传统分布式事务的一些缺陷。

在 Saga 模式中,全局事务被分解为一系列较小的本地事务,每个事务都与特定的微服务相关联。如果其中一个步骤失败,则会触发补偿操作以撤消之前的步骤,从而确保数据一致性。

Action中的 Saga 模式

为了更好地理解 Saga 模式的工作原理,让我们考虑一下预订系统。创建三个单独的 Spring Boot 项目:

  1. 预订服务: 负责办理酒店房间预订。
  2. 支付服务: 管理支付流程。
  3. Saga Orchestrator: 协调预订和支付流程的 SAGA 模式。
  4. 共享数据库 (PostgreSQL): 存储与预订和付款相关的数据。
  5. 消息代理(ActiveMQ): 处理微服务之间的异步通信。

如果任何步骤发生故障,Saga 模式将确保触发适当的补偿操作。例如,如果支付处理失败,补偿措施可能涉及取消订单或将其标记为未付款。

设置微服务

对于本示例,我们将创建两个 Spring Boot 微服务:订单服务和支付服务。每个服务都有自己的 PostgreSQL 数据库。

1.预订服务代码:

typescript 复制代码
@Service
public class BookingService {
    @Autowired
    private JmsTemplate jmsTemplate;

    @Autowired
    private BookingRepository bookingRepository;

    @Transactional
    public void makeBooking(Booking booking) {
        bookingRepository.save(booking);
        jmsTemplate.convertAndSend("bookingQueue", booking);
    }

    @Transactional
    public void confirmBooking(Long bookingId) {
        Booking booking = bookingRepository.findById(bookingId).orElse(null);
        if (booking != null) {
            booking.setConfirmed(true);
            bookingRepository.save(booking);
        }
    }

    @Transactional
    public void cancelBooking(Long bookingId) {
        Booking booking = bookingRepository.findById(bookingId).orElse(null);
        if (booking != null) {
            bookingRepository.delete(booking);
        }
    }
}

2.支付服务代码

java 复制代码
@Service
public class PaymentService {
    @Autowired
    private JmsTemplate jmsTemplate;

    @Autowired
    private PaymentRepository paymentRepository;

    @Transactional
    public void processPayment(Booking booking) {
        Payment payment = new Payment();
        payment.setBookingId(booking.getId());
        payment.setAmount(calculatePaymentAmount(booking));
        paymentRepository.save(payment);
        jmsTemplate.convertAndSend("paymentQueue", payment);
    }

    @Transactional
    public void confirmPayment(Long bookingId) {
        Payment payment = paymentRepository.findByBookingId(bookingId);
        if (payment != null) {
            payment.setPaid(true);
            paymentRepository.save(payment);
        }
    }

    @Transactional
    public void cancelPayment(Long bookingId) {
        Payment payment = paymentRepository.findByBookingId(bookingId);
        if (payment != null) {
            paymentRepository.delete(payment);
        }
    }

    private double calculatePaymentAmount(Booking booking) {
        // Implement your payment calculation logic here
        return booking.getRoomPrice() * booking.getNumNights();
    }
}

3.SagaOrchestrator服务:

less 复制代码
@Service
public class SagaOrchestrator {
    @Autowired
    private BookingService bookingService;

    @Autowired
    private PaymentService paymentService;

    @JmsListener(destination = "bookingQueue")
    public void handleBooking(Booking booking) {

    }

    @JmsListener(destination = "paymentQueue")
    public void handlePayment(Payment payment) {
        try {
                        // step 2: confirm payment is success or failed. If it's failed
                        // It's failure, throw exception and rollback.  
            paymentService.confirmPayment(payment.getBookingId());

                        // Step 3: Mark status is comfirmed in booking.
                        bookingService.confirmBooking(payment.getBookingId())
        } catch (Exception e) {
            // Handle exceptions and initiate compensation
                        bookingService.cancelBooking(booking.getId());
            paymentService.cancelPayment(payment.getBookingId());
        }
    }
}

4. 工作流程步骤:

第 1 步: 用户请求新流程预订,功能如下:makeBooking

步骤2: 流程预订创建后,用户应付款才能继续流程。

步骤3: 发送支付事件到handlePayment函数中**SagaOrchestrator**

  • 如果支付成功,确认
  • 如果支付失败,则执行回滚,取消预订和支付。

请注意,这是一个简化的示例,实际实现可能涉及更强大的错误处理、重试和监控,以实现更好的弹性和容错能力。此外,您可能需要考虑在更复杂的场景中使用 Spring Cloud State Machine 等框架或外部工具进行 SAGA 模式管理。

优点和注意事项

Saga 模式在微服务架构中提供了许多好处:

  • 去中心化:每个微服务负责其全局事务的一部分,减少了对集中协调器的需求。
  • 可扩展性:由于Saga的每一步都是本地事务,因此更容易独立扩展单个微服务。
  • 弹性:发生故障时,该模式可以通过执行补偿操作轻松恢复,确保数据一致性。
  • 性能:避免分布式事务可以提高系统性能。

不过,必须考虑到管理Saga和实施补偿操作的复杂性。此外,最终一致性也是一种权衡,并不适合所有应用。

总之,Saga 模式是在微服务架构中管理分布式事务的重要工具。它允许您保持数据一致性,同时将复杂的分布式事务分解成更小、更易于管理的步骤。通过采用 ActiveMQ 作为消息系统,可以实现微服务之间的无缝通信,确保基于微服务的应用程序的稳健性和可靠性。

相关推荐
程序员爱钓鱼37 分钟前
为什么学习 Rust?Rust 能做什么?
后端·rust
掘金者阿豪2 小时前
Docker命令太多记不住?用Portainer把容器管理变成可视化操作
后端
用户69371750013842 小时前
AI Agent 里的 Loop 到底是什么?
android·前端·后端
Rain的Java大神之路2 小时前
高并发下的抢优惠券如何设计
后端
钟智强2 小时前
AWS CloudGoat 实战:一个 SSRF 如何撬动整个云账户
后端
Ai拆代码的曹操2 小时前
@Transactional 写在 private 方法上,事务根本没生效
后端
云技纵横2 小时前
@Async 默认执行器又炸了:SimpleAsyncTaskExecutor 为什么不是线程池?
后端·面试
程序员Agions2 小时前
Fypro 新手快速上手与实战指南
后端
舒心的云朵2 小时前
用三张图片详解Asp.Net 全生命周期
后端·asp.net
卷无止境2 小时前
C++ 类型转换变迁之路:从隐式转换到 static_cast
c++·后端