微服务彻底改变了我们构建和部署软件应用程序的方式,为系统的不同部分提供了可扩展性、灵活性和独立性。然而,在微服务架构中管理分布式事务可能具有挑战性。这就是 Saga 模式发挥作用的地方。在本文中,我们将探讨 Saga 模式,并提供使用 Spring Boot 和 ActiveMQ 实现该模式的示例。
理解 Saga 模式
Saga 模式是一种用于管理微服务架构中的分布式事务的设计模式。它解决了跨多个微服务维护数据一致性的复杂性和挑战,同时避免了传统分布式事务的一些缺陷。
在 Saga 模式中,全局事务被分解为一系列较小的本地事务,每个事务都与特定的微服务相关联。如果其中一个步骤失败,则会触发补偿操作以撤消之前的步骤,从而确保数据一致性。
Action中的 Saga 模式
为了更好地理解 Saga 模式的工作原理,让我们考虑一下预订系统。创建三个单独的 Spring Boot 项目:
- 预订服务: 负责办理酒店房间预订。
- 支付服务: 管理支付流程。
- Saga Orchestrator: 协调预订和支付流程的 SAGA 模式。
- 共享数据库 (PostgreSQL): 存储与预订和付款相关的数据。
- 消息代理(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 作为消息系统,可以实现微服务之间的无缝通信,确保基于微服务的应用程序的稳健性和可靠性。