在微服务中使用 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 作为消息系统,可以实现微服务之间的无缝通信,确保基于微服务的应用程序的稳健性和可靠性。

相关推荐
2401_857636394 分钟前
计算机课程管理平台:Spring Boot与工程认证的结合
java·spring boot·后端
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
2401_857610034 小时前
多维视角下的知识管理:Spring Boot应用
java·spring boot·后端
代码小鑫4 小时前
A027-基于Spring Boot的农事管理系统
java·开发语言·数据库·spring boot·后端·毕业设计
颜淡慕潇6 小时前
【K8S问题系列 | 9】如何监控集群CPU使用率并设置告警?
后端·云原生·容器·kubernetes·问题解决
独泪了无痕6 小时前
WebStorm 如何调试 Vue 项目
后端·webstorm
怒放吧德德7 小时前
JUC从实战到源码:JMM总得认识一下吧
java·jvm·后端
代码小鑫8 小时前
A025-基于SpringBoot的售楼管理系统的设计与实现
java·开发语言·spring boot·后端·毕业设计
前端SkyRain8 小时前
后端SpringBoot学习项目-项目基础搭建
spring boot·后端·学习
梦想画家8 小时前
理解Rust 生命周期、所有权和借用机制
开发语言·后端·rust