[Camel in Action] 실전편 – Camel Saga와 분산 트랜잭션 패턴 총정리

Saga 패턴의 핵심 개념

분산 시스템에서 2PC(2-Phase Commit)는 성능과 가용성 문제로 마이크로서비스에 적합하지 않습니다. Saga 패턴은 각 서비스의 로컬 트랜잭션을 이벤트로 연결하고, 실패 시 이전 단계를 보상(취소)하는 방식으로 최종 일관성을 달성합니다.

e-커머스 주문 처리 Saga

주문 → 재고 예약 → 결제 → 배송 예약의 단계에서 어느 단계든 실패하면 이전 단계들이 자동으로 취소됩니다.

from("direct:placeOrder")
  .saga()
    .timeout(Duration.ofMinutes(5)) // 5분 내 완료되지 않으면 보상
    .compensation("direct:cancelOrder") // 실패 시 실행할 보상 라우트
    .option("orderId", header("orderId"))
  .to("direct:reserveInventory")  // 1단계: 재고 예약
  .to("direct:processPayment")    // 2단계: 결제
  .to("direct:arrangeShipping")   // 3단계: 배송 예약
  .end()
  .log("주문 완료: ${header.orderId}");

보상 라우트 구현

// 주문 취소 보상 라우트
from("direct:cancelOrder")
  .log("주문 취소 보상 시작: ${header.orderId}")
  .multicast()
    .to("direct:releaseInventory")   // 재고 예약 해제
    .to("direct:refundPayment")      // 결제 취소
    .to("direct:cancelShipping")     // 배송 취소
  .end()
  .log("주문 취소 완료: ${header.orderId}");

// 각 단계도 보상 라우트 가짐
from("direct:reserveInventory")
  .saga()
    .propagation(SagaPropagation.MANDATORY)
    .compensation("direct:releaseInventory")
  .to("bean:inventoryService?method=reserve")
  .end();

Saga 상태 영속화

Saga가 진행 중에 서버가 재시작되면 상태를 잃지 않아야 합니다. Camel Saga는 상태 저장소를 설정할 수 있습니다.

// DB 기반 Saga 저장소
JdbcSagaRepository sagaRepository = new JdbcSagaRepository(dataSource);
context.addService(sagaRepository);

// 또는 InMemory (테스트용)
InMemorySagaService sagaService = new InMemorySagaService();
context.addService(sagaService);

타임아웃과 멱등성 처리

from("direct:processPaymentStep")
  .saga()
    .propagation(SagaPropagation.MANDATORY)
    .option("sagaId", exchangeProperty(Exchange.SAGA_LONG_RUNNING_ACTION))
    .compensation("direct:refundPayment")
  .idempotentConsumer(
    exchangeProperty(Exchange.SAGA_LONG_RUNNING_ACTION),
    MemoryIdempotentRepository.memoryIdempotentRepository(1000))
  .process(exchange -> {
    // 멱등 처리: 같은 sagaId로 재시도해도 중복 결제 안 됨
    paymentService.charge(exchange.getIn().getBody(Order.class));
  })
  .end();

Saga vs 2PC 선택 기준

  • Saga 적합: 마이크로서비스, 높은 가용성, 긴 실행 트랜잭션, 최종 일관성 허용
  • 2PC 적합: 즉각적인 일관성 필수, 짧은 트랜잭션, 모든 참여자가 XA 지원

대부분의 현대 마이크로서비스 시스템에서는 Saga가 더 적합합니다. 단, UI에서 즉시 결과를 보여줘야 한다면 낙관적 UI 업데이트와 함께 사용합니다.

Leave a Comment