SAGA 패턴이란?
분산 시스템에서의 데이터 일관성을 유지하기 위한 패턴으로 마이크로서비스 아키텍처에서 중요한 역할을 한다.
장기 실행되는 트랜잭션을 처리하고, 실패 시 롤백하거나 복구하는 방법을 제공하여 시스템의 신뢰성과 안정성을 높인다.
- SAGA: 복잡한 비즈니스 트랜잭션을 여러 개의 작은 트랜잭션으로 나누어 실행. 각 작은 트랜잭션은 독립적으로 수행되며, 전체 트랜잭션이 성공적으로 완료되도록 보장한다.
- 로컬 트랜잭션: 각 작은 트랜잭션은 개별적으로 성공하거나 실패할 수 있으며, 이들은 모두 로컬 트랜잭션으로 처리된다.
- 보상 트랜잭션: 만약 어떤 작은 트랜잭션이 실패하면, 이전에 성공한 트랜잭션들을 보상하기 위해 보상 트랜잭션을 실행한다. 이를 통해 전체 트랜잭션의 일관성을 유지한다.
- 조정자: SAGA 패턴의 조정자는 트랜잭션의 흐름을 조정하고, 각 트랜잭션의 성공 여부를 확인하며, 실패 시 보상 트랜잭션을 관리한다.
SAGA Pattern 실습
1. Order에서 market.product Queue로 메세지 전달
rabbitTemplate.convertAndSend(productQueue,deliveryMessage);
2. Product에서 market.product Queue를 Listener로 수신
@RabbitListener(queues = "${message.queue.product}")
public void receiveMessage(DeliveryMessage deliveryMessage) {
log.info("PRODUCT RECEIVE: {}", deliveryMessage.toString());
productService.reduceProductAmount(deliveryMessage);
}
3. Product에서 market.payment Queue로 메세지 전달
rabbitTemplate.convertAndSend(paymentQueue,deliveryMessage);
4. Payment에서 market.payment Queue를 Listener로 수신
@RabbitListener(queues = "${message.queue.payment}")
public void receiveMessage(DeliveryMessage deliveryMessage) {
log.info("PAYMENT MESSAGE: {}", deliveryMessage);
paymentService.createPayment(deliveryMessage);
}
5. Payment에서 error 처리
if(payAmount >= 10000) {
log.error("Payment amount exceeds limit : {}", payAmount);
deliveryMessage.setErrorType("PAYMENT_LIMIT_EXCEEDED");
this.rollBackPayment(deliveryMessage);
}
6. 에러 시 market.err.product Queue로 메세지 전달
public void rollBackPayment(DeliveryMessage deliveryMessage) {
log.info("PAYMENT ROLLBACK !!!");
rabbitTemplate.convertAndSend(productErrorQueue,deliveryMessage);
}
7. Product에서 market.err.product Queue를 Listener로 수신
@RabbitListener(queues = "${message.queue.err.product}")
public void receiveErrorMessage(DeliveryMessage deliveryMessage) {
log.info("ERROR RECEIVE !!");
productService.rollbackProduct(deliveryMessage);
}
8. market.err.order Queue로 메세지 전달
rabbitTemplate.convertAndSend(errOrderQueue, deliveryMessage);
9. Order에서 market.err.order Queue를 Listener로 수신
@RabbitListener(queues = "${message.queue.err.order}")
public void errOrder(DeliveryMessage deliveryMessage) {
log.info("ERROR RECEIVE !!!");
orderService.rollbackOrder(deliveryMessage);
}
10. 해단 건 cancel 처리
public void rollbackOrder(DeliveryMessage deliveryMessage) {
Order order = orderStore.get(deliveryMessage.getOrderId());
order.cancelOrder(deliveryMessage.getErrorType());
}
오늘의 tmi)
SAGA 패턴의 흐름을 이해하기 좋은 실습이었다. 근데.. 실제 프로젝트에 어떻게 적용할지는 미지수 🙂
'TIL' 카테고리의 다른 글
[TIL] Session Clustering (0) | 2024.08.17 |
---|---|
[TIL] 모니터링 (0) | 2024.08.16 |
[TIL] Kafka란? (0) | 2024.08.15 |
[TIL] RabbitMQ 이해하기 (0) | 2024.08.13 |
[TIL] Docker란? | FeignClient DIP | Gateway FeignClient 순환참조 (0) | 2024.08.13 |