175. 사가 패턴 (Saga Pattern) - MSA 분산 트랜잭션
핵심 인사이트: 2PC(Two-Phase Commit)가 꽉 막힌 군대식 통제(블로킹)라면, 사가 패턴은 자율적인 릴레이 달리기다. '주문'이 끝나면 바통(이벤트)을 던져 '결제'가 뛰고, 결제가 실패하면 거꾸로 되돌아가면서 "취소해, 취소해!"라고 보상(Compensating) 조치를 취해 최종적인 일관성을 맞추는 MSA 시대의 트랜잭션 마스터키다.
Ⅰ. 사가 패턴 (Saga Pattern)의 개념
마이크로서비스 아키텍처(MSA)에서 각 서비스가 자신의 독립된 DB에 대한 로컬 트랜잭션만 처리한 후, 완료 이벤트를 비동기(메시지 큐)로 발행하여 다음 서비스의 로컬 트랜잭션을 연쇄적으로 트리거(트랜잭션 쪼개기) 하는 방식입니다. 만약 중간 서비스에서 에러가 발생하면, 이전에 성공했던 서비스들에게 '보상 트랜잭션(Compensating Transaction, 롤백 연산)' 이벤트를 거꾸로 발행하여 데이터의 최종 일관성(Eventual Consistency)을 맞춥니다.
Ⅱ. 사가 패턴의 동작 (성공 vs 실패)
[상품 구매 시나리오: 주문 ➔ 결제 ➔ 배송]
-
정상 흐름 (Forward Recovery)
- ① [주문 서비스]가 주문 DB에
주문생성저장 후 ➔ Kafka에[주문됨]이벤트 발행 - ② [결제 서비스]가
[주문됨]이벤트를 듣고 결제 DB에결제완료저장 후 ➔ Kafka에[결제됨]이벤트 발행 - ③ [배송 서비스]가
[결제됨]이벤트를 듣고 배송 DB에배송준비저장. (완벽한 성공!)
- ① [주문 서비스]가 주문 DB에
-
실패 흐름과 보상 트랜잭션 (Backward Recovery)
- ① [주문 서비스] 성공 (주문생성) ➔
[주문됨] - ② [결제 서비스]가 결제를 시도했으나 잔액 부족으로 실패!
- ③ 🚨 [결제 서비스]는 즉시 Kafka에
[결제실패]라는 보상 이벤트를 발행합니다. - ④ [주문 서비스]가 이
[결제실패]이벤트를 듣고, 자신의 주문 DB를주문취소상태로 UPDATE 합니다. (물리적 ROLLBACK이 아님!)
- ① [주문 서비스] 성공 (주문생성) ➔
Ⅲ. 물리적 Rollback과의 차이 (보상 트랜잭션의 본질)
사가 패턴에서의 '취소'는 DB의 롤백(ROLLBACK) 명령어가 아닙니다.
이미 주문 서비스의 로컬 트랜잭션은 1단계에서 끝(COMMIT)났기 때문에 되돌릴 수 없습니다. 따라서 기존 작업을 논리적으로 상쇄하는 반대 성격의 쿼리(예: INSERT 했으면 DELETE, 상태가 진행중이면 취소로 UPDATE)를 새롭게 실행하는 것을 보상 트랜잭션이라고 부릅니다.
Ⅳ. 최종 일관성 (Eventual Consistency)의 의미
사가 패턴은 트랜잭션 도중 아주 짧은 찰나(예: 주문은 생성됐는데 결제가 실패하기 전 0.5초 동안)에는 고객 화면에 주문이 성공한 것처럼 보이는 '불일치 순간' 이 존재합니다. 하지만 이벤트가 돌고 돌면 "결국(Eventually)에는 무조건 일관성이 맞춰진다" 는 철학으로, 시스템의 동기적 대기(블로킹)를 완전히 없애 엄청난 트래픽을 처리하는 MSA의 핵심 사상입니다.
📢 섹션 요약 비유: 2PC가 3명이 현관문에 손잡고 서서 "셋 다 신발 신었으면 다 같이 나가자(Lock)"라면, 사가 패턴은 첫째가 먼저 문을 열고 나간 뒤(Commit), 둘째에게 "나 나왔어(이벤트)"라고 소리치는 것입니다. 만약 셋째가 "나 배 아파서 못 나가!"라고 소리치면, 이미 밖에 나간 첫째와 둘째가 터덜터덜 집 안으로 다시 들어와서 문을 닫는(보상 트랜잭션) 방식입니다. 중간에 잠깐 떨어져 있는 시간은 생기지만 기다리는 낭비는 사라집니다.