분산 트랜잭션 패턴(2PC,TCC,SAGA)

분산 트랜잭션 패턴 2PC, TCC ,saga의 개념 정리

분산 트랜잭션 패턴(2PC,TCC,SAGA)

Intro

보통 “트랜잭션” 이라는 단어를 들으면, RDB의 트랜잭션을 먼저 떠올려요.
모든 변경 사항을 영구적으로 저장하고, 오류 발생 시 깔끔하게 롤백을 보장하는 DB의 핵심 개념이죠.

하지만 이건 하나의 DB 안에서만 가능한 이야기고
여러 서비스가 서로 다른 애플리케이션과 DB를 가지고 있는 분산 구조에서는 불가능해요.
이를 극복하기 위해 분산 환경에서도 하나의 트랜잭션처럼 동작하도록 하는 분산 트랜잭션이 등장했어요.

이 글에서는 사용되는 대표적 분산 트랜잭션 패턴들 ― 2PC, TCC, SAGA ― 를 정리할 거예요.


2PC (two-phase-commit)

가장 먼저 등장한 트랜잭션 패턴이에요. 현재는 잘 쓰이지 않아요!!

2PC는 중앙 Coordinator가 Prepare 단계를 통해 각 참여자들이 준비가 됐는지 확인하고, 모두 OK면 Commit 단계에서 실제로 반영, 오류가 있다면 전부 롤백해요.

가장 간단하고 직관적이지만, PostgreSQL의 PREPARE TRANSACTION, MySQL의 XA TRANSACTION 처럼 DB 자체가 2PC를 구현해야 하고, DB의 트랜잭션을 오래 잡아두는 방식이라 가용성이 낮아, 실제로는 거의 쓰이지 않아요.

이제부터는 주문, 재고, 포인트 시스템을 예시로 설명할 거예요.
주문 시 재고가 차감되고, 포인트가 소모되면서 주문이 생성되는 시나리오예요.
즉, 주문 생성, 재고 차감, 포인트 사용은 모두 함께 성공하거나, 모두 함께 실패해야 해요.

TCC (Try-Confirm-Cancel)

TCC는 자원을 먼저 예약(Try) 하고, 그 후 확정(Confirm) 하거나 취소(Cancel)하는 방식이에요.

여기서 "예약” 이란, 실제 자원을 소비하지는 않지만, 다른 요청이 예약된 자원에 접근할 수 없도록 홀딩하는 걸 말해요.

시나리오는 다음과 같아요:

  • Try: 각 시스템에서 주문, 재고, 포인트를 임시로 예약해요.
  • Confirm: Try 과정이 성공했을 경우, 각 서비스에 확정 요청을 보내요 ⇒ 예약된 항목을 실제 반영해요.
  • Cancel: Try과정에서 오류가 발생하면, 예약했던 내역을 해제해요.

Confirm/Cancel이 확정됐다면, 모든 서비스로 반드시 Confirm/Cancel 상태가 전파되어야 해요. 즉, 네트워크 오류가 발생하거나 컴퓨터가 터져도? 재시도, 수동 개입 등으로 일관된 상태를 보장해야 해요.

장단점

  • 장점
    • 자원을 먼저 “예약”하고 확정되면 반영해서 잘못된 자원 점유가 전파되지 않아요.
    • 오류 발생 시 단순히 예약을 해제하므로, 보상 과정이 실패할 염려가 낮아요.
  • 단점
    • 모든 서비스가 TCC 3단계를 구현해야 해 설계와 구현이 복잡해요.
    • 중간 Confirm 단계로 인해 호출 횟수가 1회 더 필요해요.

Saga

Saga는 일단 자원을 소비하고, 오류가 발생하면 보상(롤백) 트랜잭션을 사용해 되돌리는 방식이에요.

TCC와 거의 비슷해 보이는데, TCC는 Confirm 단계 전까지 실제 자원을 소비하지 않는 반면, Saga는 일단 자원을 소비하고 문제가 생기면 되돌리는 거죠.

시나리오는 다음과 같아요:

  1. 각 시스템에서 주문, 재고 포인트를 모두 “소비” 해요. 모두 성공했다면 그걸로 끝나요.
  2. 오류가 발생하면, 주문을 취소하고 재고와 포인트를 앞서 소비한 만큼 다시 복구해요.

장단점

  • 장점:
    • TCC와 비교해서 API 구조가 단순해요
    • 성공 시나리오에서는 1회 호출로 끝나요.
  • 단점:
    • 자원을 실제로 “소비” 하므로, 보상 과정에서 데이터 불일치가 생길 수 있어요.
    • 자원 소비 시 외부 사이드이펙트가 있다면, 보상 시 완전한 원상복구는 어려울 수 있어요.

TMI

Saga는 크게 Orchestration 방식과 Choreography 방식으로 나눌 수 있어요.

간단히 살펴보면:

  • Orchestration: 중앙에서 Orchestrator가 흐름을 제어하는 방식이에요.예를 들어, 주문 서비스가 재고와 포인트 서비스에 각각 요청하고 그 결과를 조합하는 식이죠.결과를 즉시 사용자에게 반환해야 할 때 적합하지만, 서비스 간 과도한 결합이 생길 수 있어요.
  • Choreography: 각 서비스들이 이벤트 기반으로 독립적으로 동작하는 방식이에요.예를 들어, 주문 → 재고 → 포인트 → 주문 같은 이벤트 흐름으로 이어져요.메시지 큐(MQ) 방식을 사용해 결합도는 낮지만, 전체 이벤트 흐름을 한눈에 추적하기 어려워요.

그럼 어떤 패턴을 사용할까?

  • 2PC는 가용성이 낮아 거의 쓰이지 않아요.
  • TCC는 정합성이 특히 중요한 경우에 제한적으로 사용해요.
  • Saga를 가장 널리 사용해요.
    • Choreography 방식: 비동기 처리에 적합하고, 워크플로우가 단순할 때 잘 맞아요.
    • Orchestration 방식: 동기 처리이거나 트랜잭션 시나리오가 복잡할 때, 중앙에서 흐름과 보상 로직을 관리하기 위해 주로 사용해요.

Final

앞서 설명한 모든 패턴들은 오류가 발생할 수밖에 없어요.

  • 2PC ⇒ DB 1의 Commit이 성공했는데, DB 2가 죽어버렸다면?
  • TCC ⇒ 예약은 전부 성공했는데, Point Service의 Confirm 단계에서 네트워크가 끊긴다면?
  • SAGA ⇒ Point 차감이 실패했는데, Product에 보상 메시지가 전달되지 않는다면?

아무리 코드를 잘 짜고, 시스템을 완벽하게 설계해도 분산 트랜잭션에서는 오류를 완전히 피할 수 없어요.

따라서 분산 시스템 개발 시엔 자동 재시도를 충분히 설계하고, 최악의 경우엔 수동으로 개입할 수 있는 관리 체계도 준비돼 있어야 해요.

3-Point

  1. 분산 트랜잭션 패턴 2PC, TCC, SAGA에 대해 알아봤다.
  2. 분산 트랜잭션은 오류가 생길 수밖에 없다. 이를 처리하는 것이 핵심이다.
  3. 언젠가 실무에서 직접 적용해보고 싶다.