분산 트랜잭션 제어 - 보상적 트랜잭션

유호빈·2024년 5월 21일
0

현재 프로젝트는 MSA 환경으로 되어 있기 때문에 사용자가 주문 요청 시 product service에는 재고 감소를 요청하고, payment service에는 결제 시작을 요청합니다.

다른 서비스로 요청 시 kafka 이벤트를 이용하고 있습니다. 하지만, 재고 감소에서의 실패나 결제 진입 시 실패와 같이 다른 서비스에서 예외가 발생한다면 분산 환경이기 때문에 트랜잭션을 롤백할 수 없습니다.

1. SAGA 패턴

SAGA 패턴은 마이크로서비스끼리 이벤트를 주고 받을 때 특정 마이크로서비스에서 작업이 실패하면 이전의 다른 마이크로서비스에서 완료된 작업에 대해 보상 이벤트를 발행해 데이터 일관성을 보장하는 패턴입니다.

SAGA 패턴에는 크게 2가지 종류인 Orchestration과 Choreography가 존재하지만 이번 포스팅에서는 Choreography 방식을 사용합니다.

Choreography 방식은 SAGA 인스턴스가 별도로 존재하지 않고 각 서비스 끼리 이벤트 pub/sub을 통해 통신합니다.

2. 프로젝트 적용

프로젝트는 위의 그림과 같이 주문 요청 시 order-service 에서 주문을 생성하고 product-service와 payment-service로 kafka를 통해 이벤트 요청을 보내고 있습니다.

Payment Kafka Listener

주문 서비스에서 결제 요청 시 코드는 다음과 같습니다.

	@KafkaListener(topics = "${env.kafka.consumer.topic.process-payment}")
    public void processPayment(String message) {
        log.info("kafka listener process payment message ={}", message);
        ProcessPaymentRequest processPaymentRequest = null;
        try {
            processPaymentRequest = objectMapper.readValue(message, ProcessPaymentRequest.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        try {
            paymentService.processPayment(processPaymentRequest);
        } catch (BusinessException e) {
            log.error("BusinessException",e);
            eventProvider.produceEvent(new OrderCancelEvent(processPaymentRequest.getOrderId()));
        }
    }

@KafkaListener를 통해 메시지를 구독해 결제 엔티티를 생성하는 로직입니다. 결제 생성 시 예외가 발생한다면 catch문 내의 event를 다시 발행합니다.

	@TransactionalEventListener(classes = OrderCancelEvent.class, phase = TransactionPhase.BEFORE_COMMIT)
    @Async
    public void handle(OrderCancelEvent orderCancelEvent) {
        kafkaTemplate.send(orderCancelTopic, String.valueOf(orderCancelEvent.getOrderId()));
        log.info("Kafka PaymentProducer send Data for rollback created order: " + orderCancelEvent.getOrderId());
    }

주문을 다시 롤백하는 이벤트를 발행하고 주문 서비스에서는 이를 구독하고 있어 해당 이벤트가 발생하면 주문을 다시 롤백합니다.

profile
시작하자

0개의 댓글