SAGA 패턴은 분산 시스템에서 여러 서비스에 걸친 장기 트랜잭션을 일련의 로컬 트랜잭션과 보상(Compensation) 트랜잭션으로 구현하는 패턴이다.
SAGA vs 2PC
| 항목 | 2PC | SAGA |
|---|
| 일관성 | 강한 일관성 | 최종 일관성 |
| 결합도 | 참여자 모두 동기 대기 | 비동기 |
| 가용성 | 낮음 (코디네이터 SPF) | 높음 |
| 확장성 | 낮음 | 높음 |
| 복잡도 | 낮음 | 높음 (보상 트랜잭션) |
| 적합 | 단일 DB | 마이크로서비스 |
두 가지 구현 방식
1. 코레오그래피 (Choreography):
각 서비스가 이벤트 발행/구독으로 자율 조정
장점: 중앙 조정자 없음, 느슨한 결합
단점: 흐름 추적 어려움, 순환 의존 위험
2. 오케스트레이션 (Orchestration):
Saga Orchestrator가 각 서비스 호출 지시
장점: 중앙 흐름 제어, 추적 용이
단점: Orchestrator가 복잡해짐
typescript
// Saga Orchestrator
class OrderSaga {
async execute(orderId: string) {
const steps = [
{ exec: () => paymentSvc.reserve(orderId), comp: () => paymentSvc.refund(orderId) },
{ exec: () => inventorySvc.reserve(orderId), comp: () => inventorySvc.release(orderId) },
{ exec: () => shippingSvc.schedule(orderId), comp: () => shippingSvc.cancel(orderId) },
];
const completed: number[] = [];
for (let i = 0; i < steps.length; i++) {
try {
await steps[i].exec();
completed.push(i);
} catch (err) {
// 역순 보상 실행
for (const j of completed.reverse()) {
await steps[j].comp().catch(e => log.error('Compensation failed', e));
}
throw new SagaFailedError(orderId, i, err);
}
}
}
}
보상 트랜잭션 설계 원칙
멱등성 (Idempotent):
같은 보상을 여러 번 실행해도 동일한 결과
보상 ID를 기록하여 중복 실행 방지
실패한 보상 처리:
보상도 실패 가능 → Dead Letter Queue
수동 개입 필요 (알림 발송)
보상 불가 트랜잭션 (Pivot):
이메일 발송, 환불 확인 메시지 → 되돌리기 불가
→ Saga에서 가능한 마지막에 배치
관련 문서
- •[[two-phase-commit|2PC]]
- •[[three-phase-commit|3PC]]
- •[[event-driven-architecture|이벤트 주도 아키텍처]]