在微服务中使用 Spring Boot 和 ActiveMQ 实现 Saga 模式
微服务彻底改变了我们构建和部署软件应用程序的方式,为系统的不同部分提供了可扩展性、灵活性和独立性。然而,在微服务架构中管理分布式事务可能颇具挑战性。这正是 Saga 模式发挥作用的地方。在本文中,我们将探讨 Saga 模式,并提供使用 Spring Boot 和 ActiveMQ 实现它的示例。
理解 Saga 模式
Saga 模式是一种用于管理微服务架构中分布式事务的设计模式。它解决了跨多个微服务维护数据一致性的复杂性和挑战,同时避免了传统分布式事务的缺陷。
在 Saga 模式中,全局事务被分解为一系列较小的本地事务,每个事务都与特定的微服务关联。如果某个步骤失败,则会触发补偿操作来撤消之前的步骤,从而确保数据一致性。
Saga 模式的实际应用
为了更好地理解 Saga 模式的工作原理,我们来考虑一个预订系统。创建三个独立的 Spring Boot 项目,分别用于:
- 预订服务:负责处理酒店客房预订。
- 支付服务:管理支付流程。
- Saga Orchestrator:为预订和付款流程协调 SAGA 模式。
- 共享数据库(PostgreSQL):存储与预订和付款相关的数据。
- 消息代理(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);
}
}
}
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();
}
}
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());
}
}
}
4.工作流程分步说明:
步骤 1:用户使用以下功能请求新的流程预订:makeBooking
第 2 步:创建流程预订后,用户应付款才能继续流程。
步骤 3:将付款事件发送handlePayment
到SagaOrchestrator
- 如果付款成功,确认
- 若支付失败,则执行回滚,取消预订及支付。
请注意,这是一个简化的示例,实际实现可能涉及更强大的错误处理、重试和监控,以实现更好的弹性和容错能力。此外,在更复杂的场景中,您可能需要考虑使用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