사가 (Saga) 패턴 2PC 한계 극복 분산 트랜잭션

핵심 인사이트 (3줄 요약)

  1. 본질: 사가(Saga) 패턴은 마이크로서비스 아키텍처(MSA)에서 여러 서비스에 걸친 긴 트랜잭션을 처리하기 위해, 각 서비스의 로컬 트랜잭션을 순차적으로 실행하고 실패 시 **보상 트랜잭션(Compensating Transaction)**을 통해 논리적 롤백을 수행하는 분산 트랜잭션 패턴이다.
  2. 가치: 전통적인 2PC(Two-Phase Commit)가 가진 동기적 블로킹과 자원 락(Lock)으로 인한 성능 저하 한계를 극복하고, 시스템의 가용성(Availability)과 확장성을 유지하면서 최종 일관성(Eventual Consistency)을 확보할 수 있게 해준다.
  3. 융합: 사가 패턴은 중앙에서 흐름을 통제하는 오케스트레이션(Orchestration) 방식과 이벤트 기반으로 자율적으로 동작하는 코레오그래피(Choreography) 방식으로 나뉘며, 비동기 메시징 큐(Kafka, RabbitMQ) 및 아웃박스(Outbox) 패턴과 결합하여 구현된다.

Ⅰ. 개요 및 필요성 (Context & Necessity)

  • 개념: 사가(Saga)는 단일 데이터베이스의 ACID(원자성, 일관성, 고립성, 지속성) 트랜잭션을 여러 서비스에 걸쳐 분할한 연속된 로컬 트랜잭션의 체인이다. 만약 중간 단계에서 비즈니스 규칙 위반(예: 잔고 부족)으로 실패하면, 이전에 성공했던 트랜잭션들을 되돌리기 위해 역순으로 보상 트랜잭션을 실행한다.

  • 필요성: MSA에서는 '주문(Order)', '결제(Payment)', '재고(Inventory)' 서비스가 각각 독립적인 데이터베이스를 갖는다(Database per Service). 고객이 주문을 할 때 세 가지 DB가 모두 성공적으로 업데이트되어야 하는데, 이를 전통적인 분산 트랜잭션 기법인 2PC로 묶으면, 하나라도 지연될 경우 세 개의 DB에 모두 락(Lock)이 걸려 시스템 전체가 마비(Deadlock 위험 및 Throughput 저하)된다. 따라서 락을 걸지 않고도 데이터의 정합성을 맞출 대안이 필수적이다.

  • 💡 비유: 친구들과 해외여행을 준비할 때, 한 명이 '항공권', '호텔', '렌터카'를 한 번에 동시에 예약(2PC)하려 하면 하나라도 자리가 날 때까지 아무것도 못 하고 기다려야 합니다. 반면 사가 패턴은 먼저 항공권을 예약(성공)하고, 다음으로 호텔을 예약하려는데 방이 없으면, **앞서 예약해둔 항공권을 취소(보상 트랜잭션)**하는 방식과 같습니다.

  • 등장 배경 및 발전 과정:

    1. 단일 DB와 2PC (Two-Phase Commit): 과거 XA 프로토콜 기반의 2PC는 완벽한 일관성을 보장했으나, MSA의 클라우드 환경에서는 성능 저하와 NoSQL 등 미지원 DB의 등장으로 사용이 불가능해졌다.
    2. BASE와 최종 일관성 (Eventual Consistency): 분산 시스템에서는 항상 즉각적인 일관성을 보장하기보다, "결국에는(Eventual) 일치하게 된다"는 비동기적 철학이 대두되었다.
    3. Saga 패턴의 재조명: 1987년 논문에서 처음 등장한 장기 실행 트랜잭션 모델인 Saga가 MSA 시대에 이벤트 기반 아키텍처(EDA)와 결합하며 분산 트랜잭션의 표준 해결책으로 부활했다.
  • 📢 섹션 요약 비유: 도미노를 세우다가 중간에 하나가 무너지면, 뒤로 계속 무너지는 것이 아니라 관리자가 재빨리 뛰어가 앞서 세워둔 도미노들을 안전하게 눕혀놓아 원상태로 복구하는 것과 같습니다.


Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)

구성 요소

요소명역할내부 동작관련 기술비유
로컬 트랜잭션 (Local Tx)단일 마이크로서비스 내부 DB에서의 ACID 트랜잭션데이터 변경 및 이벤트 발행Spring @Transactional각자의 방에서 하는 청소
보상 트랜잭션 (Compensating Tx)이미 커밋된 로컬 트랜잭션의 결과를 논리적으로 취소(역산)예: 결제 승인 → 결제 취소, 재고 차감 → 재고 증가비즈니스 로직결제된 카드를 승인 취소함
코레오그래피 (Choreography)각 서비스가 이벤트를 구독하고 자율적으로 다음 행동을 결정펍/섭 (Pub/Sub) 브로커를 통한 비동기 통신Kafka, RabbitMQ지휘자 없는 댄서들의 군무
오케스트레이션 (Orchestration)중앙 통제기(Orchestrator)가 트랜잭션의 흐름과 보상을 명령상태 기계(State Machine) 기반 작업 조율AWS Step Functions, Camunda오케스트라 지휘자

사가 패턴 구현 방식 1: 코레오그래피 (Choreography)

코레오그래피 방식은 중앙의 통제자 없이, 각 서비스가 다른 서비스의 **이벤트(Event)**를 듣고 자신의 로컬 트랜잭션을 실행한 뒤 다음 이벤트를 발행하는 방식이다.

  ┌───────────────────────────────────────────────────────────────┐
  │        코레오그래피 (Choreography) Saga 흐름 (주문 실패 시나리오)   │
  ├───────────────────────────────────────────────────────────────┤
  │                                                               │
  │   [Order Svc]            [Payment Svc]           [Inventory Svc]│
  │   1. 주문 생성(PENDING)                                         │
  │   2. OrderCreatedEvent ──▶                                    │
  │                          3. 결제 시도 (성공)                     │
  │                          4. PaymentBilledEvent ─▶             │
  │                                                  5. 재고 확인 (실패!)│
  │                                                  6. InventoryFailedEvent │
  │  ◀───────────────────────────(보상 시작)─────────────────────────┘│
  │                          7. [보상] 결제 취소                    │
  │  ◀── PaymentRefundedEvent ───                                 │
  │   8. [보상] 주문 취소(CANCELED)                                 │
  │                                                               │
  │   * 특징: 지휘자 없이 서로의 이벤트를 듣고 알아서 행동함!            │
  └───────────────────────────────────────────────────────────────┘
  • 장점: 결합도가 낮고, 중앙 병목(SPOF)이 없다. 간단한 트랜잭션에 적합하다.
  • 단점: 참여하는 서비스가 많아지면 이벤트의 흐름을 추적하기 매우 어려워진다(이벤트 스파게티).

사가 패턴 구현 방식 2: 오케스트레이션 (Orchestration)

오케스트레이션 방식은 Order Saga Orchestrator라는 중앙 관리자가 존재하여, 각 서비스에게 무엇을 해야 할지 **명령(Command)**을 내리고 결과를 받아 다음 단계를 제어한다.

  ┌───────────────────────────────────────────────────────────────┐
  │        오케스트레이션 (Orchestration) Saga 흐름 (주문 실패 시나리오)│
  ├───────────────────────────────────────────────────────────────┤
  │                                                               │
  │                 ┌────────────────────────┐                    │
  │                 │ Order Saga Orchestrator│ (상태 관리자)         │
  │                 └────────────────────────┘                    │
  │                   │     ▲    │     ▲    │    ▲                │
  │      1.결제명령(Cmd)│     │    │     │    │    │ 6.재고실패 응답  │
  │                   ▼     │    │     │    ▼    │                │
  │    ┌───────────────┐    │    │     │  ┌───────────────┐       │
  │    │ Payment Svc   │────┘    │     │  │ Inventory Svc │       │
  │    │ (결제 성공)    │ 2.성공응답│     │  │ (재고 부족!)    │       │
  │    └───────────────┘         ▼     │  └───────────────┘       │
  │                   3.재고명령(Cmd)   │                         │
  │                                    │                          │
  │                   7.결제취소명령(Cmd) │                          │
  │                   (보상 트랜잭션 시작) ▼                          │
  │    ┌───────────────┐               ┌───────────────┐          │
  │    │ Payment Svc   │               │ Order Svc     │          │
  │    │ (결제 취소 처리)│               │ (주문 상태 취소)│          │
  │    └───────────────┘               └───────────────┘          │
  │                                                               │
  │   * 특징: Orchestrator가 전체 워크플로우와 보상 순서를 책임짐!      │
  └───────────────────────────────────────────────────────────────┘
  • 장점: 복잡한 트랜잭션 흐름(예: 5개 이상 서비스 참여)도 한 곳에서 추적 가능하며, 순환 참조 문제가 없다.

  • 단점: Orchestrator가 слишком 많은 비즈니스 로직을 가지면 또 다른 모놀리스(Smart Orchestrator, Dumb Services)가 될 위험이 있다.

  • 📢 섹션 요약 비유: 코레오그래피가 신호등(이벤트)을 보고 알아서 차들이 움직이는 교차로라면, 오케스트레이션은 교통경찰(지휘자)이 수신호로 어느 차가 가고 멈출지를 일일이 지시하는 교차로입니다.


Ⅲ. 실무 적용 및 기술사적 판단

실무 시나리오

  1. 시나리오 — 보상 트랜잭션의 실패: 주문 취소로 인해 '결제 취소' 보상 트랜잭션을 실행했는데, PG사 네트워크 오류로 결제 취소가 실패한 상황.

    • 판단: 보상 트랜잭션은 본질적으로 실패할 수 있다. 분산 시스템에서 '절대 실패하지 않는 것'은 불가능하다.
    • 해결책: 보상 트랜잭션은 반드시 **멱등성(Idempotency)**을 보장하도록 설계되어야 한다. 네트워크 오류 시 무한 재시도(Retry)를 하거나, 실패 내역을 Dead Letter Queue(DLQ)에 쌓아두고 관리자가 수동(Manual Intervention)으로 개입할 수 있는 배치/어드민 알림 프로세스를 마련해야 한다.
  2. 시나리오 — 격리성(Isolation) 부재로 인한 Dirty Read: 사가 패턴 진행 중, 주문은 생성되었으나 아직 재고 확인이 끝나지 않은 시점에, 다른 트랜잭션이나 사용자가 해당 '주문' 데이터를 읽고 처리해버린 상황.

    • 판단: 사가 패턴은 ACID 중 고립성(Isolation)이 부족하다. 즉, 트랜잭션 중간 상태가 외부에 노출(Dirty Read)된다.
    • 해결책: 시맨틱 락(Semantic Lock) 기법을 사용한다. 레코드의 상태 플래그를 CREATED 대신 PENDING이나 PROCESSING으로 표기하여, 다른 트랜잭션이 이 레코드를 섣불리 읽거나 수정하지 못하도록 비즈니스 로직 단에서 통제해야 한다.

도입 체크리스트

  • 기술적: 이벤트 발행 시 DB 커밋과 메시지 전송의 원자성을 보장하기 위해 아웃박스(Outbox) 패턴이 결합되어 있는가? (메시지 유실 방지)
  • 아키텍처적: 서비스의 개수가 3~4개 이하로 적고 워크플로우가 고정적이라면 코레오그래피를, 5개 이상이거나 보상 로직 분기가 매우 복잡하다면 오케스트레이션을 선택했는가?

안티패턴

  • 오케스트레이터의 갓 객체(God Object)화: 오케스트레이터가 흐름 제어뿐만 아니라 '재고가 부족하면 대체 상품을 제안한다' 같은 타 도메인의 핵심 비즈니스 로직까지 품어버려, 결국 모든 코드가 오케스트레이터로 집중되는 안티패턴.

  • 📢 섹션 요약 비유: 식당에서 주문이 잘못 들어갔을 때, 환불(보상 트랜잭션) 처리가 전산 오류로 안 될 수도 있기 때문에, 점장님(관리자)이 나중에 장부를 보고 직접 돈을 돌려줄 수 있는 수동 절차(DLQ/배치)도 반드시 준비해 두어야 합니다.


Ⅳ. 기대효과 및 결론

정량/정성 기대효과

구분전통적인 2PC 분산 트랜잭션사가(Saga) 패턴개선 효과
정량모든 DB에 Lock 유지 (수 초 소요)로컬 DB만 Lock 점유 후 즉시 해제시스템 동시 처리량(Throughput) 수십~수백 배 증가
정량단일 서비스 장애 시 전체 트랜잭션 대기비동기 기반 보상 처리시스템 전체의 가용성(Availability) 방어
정성DB 기술 종속적 (NoSQL 적용 불가)애플리케이션 레벨의 논리적 롤백RDBMS와 NoSQL 간의 트랜잭션 연동 가능

사가 패턴은 MSA에서 데이터를 나누었을 때 직면하는 가장 큰 고통(데이터 정합성)에 대한 현실적인 타협안이다. 완벽한 ACID를 포기하는 대신 BASE(Basic Availability, Soft-state, Eventual consistency) 철학을 받아들여 시스템의 성능과 생존성을 높인다. 기술사는 "왜 2PC를 쓰지 않느냐"는 질문에 동기식 락(Lock)의 위험성을 설명하고, 사가 패턴의 멱등성과 보상 실패 시나리오까지 대비된 아키텍처를 제시할 수 있어야 한다.


📌 관련 개념 맵 (Knowledge Graph)

개념 명칭관계 및 시너지 설명
2PC (Two-Phase Commit)사가 패턴이 극복하고자 하는 과거의 동기식 분산 트랜잭션 모델로, 완벽한 일관성을 주지만 성능을 희생한다.
이벤트 주도 아키텍처 (EDA)사가 패턴 중 코레오그래피 방식을 구현하기 위한 기반 아키텍처로 비동기 메시지 큐(Kafka)를 사용한다.
아웃박스 패턴 (Outbox Pattern)로컬 트랜잭션 완료와 보상 트랜잭션 유발을 위한 이벤트 발행이 100% 원자적으로 일어나도록 보장하는 연계 패턴이다.
멱등성 (Idempotency)보상 트랜잭션이 여러 번 재시도되더라도 최종 결과가 같음을 보장하여, 분산 환경의 네트워크 에러를 방어하는 핵심 속성이다.
최종 일관성 (Eventual Consistency)사가 패턴 실행 도중에는 데이터가 불일치할 수 있으나, 결국 보상이나 성공으로 마무리되어 데이터가 맞춰지는 상태다.

👶 어린이를 위한 3줄 비유 설명

  1. 레고로 큰 성을 만들 때, 친구들 3명이 각자 방에서 '탑', '벽', '문'을 만들어서 나중에 하나로 합치기로 했어요.
  2. 만약 한 친구가 블록이 모자라서 '문'을 못 만들게 되면, 나머지 친구들도 만들던 '탑'과 '벽'을 모두 부수고 처음 상태로 되돌려 놓기로 약속했어요.
  3. 이렇게 서로 멀리 떨어져서 일하다가 한 명이라도 실패하면, 다 같이 약속한 대로 자기가 만든 걸 예전으로 되돌리는 똑똑한 방법을 '사가(Saga) 패턴'이라고 한답니다.