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

2025-06-09

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

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

理解 Saga 模式

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

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

Saga 模式的实际应用

为了更好地理解 Saga 模式的工作原理,我们来考虑一个预订系统。创建三个独立的 Spring Boot 项目,分别用于:

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

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

设置微服务

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

1.预订服务代码:

@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);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

2.支付服务代码

@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();
    }
}
Enter fullscreen mode Exit fullscreen mode

3. SagaOrchestrator 服务:

@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());
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

4.工作流程分步说明:

步骤 1:用户使用以下功能请求新的流程预订:makeBooking

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

步骤 3:将付款事件发送handlePaymentSagaOrchestrator

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

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

好处和注意事项

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

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

然而,必须考虑管理 Saga 和实施补偿操作的复杂性。此外,最终一致性是一种权衡,它可能并不适合所有应用程序。

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

鏂囩珷鏉ユ簮锛�https://dev.to/jackynote/implementing-the-saga-pattern-with-spring-boot-and-activemq-in-microservice-14me
PREV
使用 Lighthouse CI 和 Github Actions 在 Nuxt 2 中进行持续性能检查
NEXT
将你的 dev.to 文章更新到你的 Github 个人资料中