9. 질문 — CAP 정리와 분산 트랜잭션 (Saga, 2PC)
난이도 최상내 답안
모범답안
모범답안 — CAP 정리와 분산 트랜잭션 (Saga / 2PC)
난이도: 최상
핵심 답변
CAP: 네트워크 분단(P)이 발생하면 일관성(C)과 가용성(A)을 동시에 만족할 수 없다 — 분단 중엔 "오래된 답이라도 줄지(A)" "응답을 거부하고 일관성을 지킬지(C)" 택해야 한다. 분산에서 분단은 언제든 일어나므로 P는 필수, 결국 CP냐 AP냐의 선택이다. 재화처럼 정확성이 생명인 데이터는 CP(강한 일관성), 채팅·랭킹처럼 잠깐 어긋나도 되는 건 AP(최종 일관성). 교차 트랜잭션은 2PC(강하지만 느리고 블로킹) 또는 **Saga(보상 트랜잭션으로 최종 일관성)**로 처리한다.
깊이 있는 설명
CAP 정리
- C(일관성): 모든 노드가 같은 최신 데이터를 본다.
- A(가용성): 모든 요청이 (성공이든) 응답을 받는다.
- P(분단 내성): 노드 간 메시지가 끊겨도 시스템이 동작.
- 분단이 없을 땐 C와 A 둘 다 가능. 분단이 나면 둘 중 하나를 포기해야 한다. 실무에선 "분단 시 어느 쪽을 택하느냐"로 이해하는 게 정확(PACELC로 확장: 분단이 없을 땐 지연 vs 일관성 트레이드오프).
강한 vs 최종 일관성
- 강한 일관성: 항상 최신값. 대신 지연·가용성 비용(합의·락).
- 최종 일관성: 잠시 어긋나도 결국 수렴. 빠르고 가용하지만 "방금 산 아이템이 잠깐 안 보임" 같은 현상.
- 게임 매핑: 재화·결제·아이템=강한 일관성, 랭킹·통계·채팅·존재감(presence)=최종 일관성 허용.
2PC vs Saga
- 2PC: 코디네이터가 모든 참여자에게 prepare→commit. 원자성은 강하지만 블로킹(코디네이터 장애 시 참여자가 락을 잡고 대기), 지연·확장성 약함. 게임 핫패스엔 부적합, 드문 정합성 작업에 제한적.
- Saga: 큰 트랜잭션을 로컬 트랜잭션들의 시퀀스로 쪼개고, 중간 실패 시 보상(compensating) 트랜잭션으로 되돌린다. 예: 골드 차감(로컬) → 아이템 지급(로컬), 실패하면 골드 환불. 최종 일관성·비블로킹·확장성↑. 단 중간 상태가 잠깐 노출되고, 보상 로직을 직접 설계해야 함.
분산 exactly-once 근사
- 각 단계에 멱등 키(거래ID) 부여 → 재시도해도 한 번만 반영(DB UNIQUE·dedup).
- 차감/지급을 로컬 트랜잭션 + 아웃박스(outbox) 로 묶어 "DB 커밋과 이벤트 발행"을 원자화, 소비자는 멱등.
- 외부 펜싱 토큰/버전으로 stale 노드의 중복 처리 차단.
응용/실무 연결
- 교차 서버 거래: Saga + 에스크로(중간 보관) + 멱등 키. 양쪽이 commit/ack 전까지 아이템을 "잠금" 상태로.
- 결제 → 재화 지급: 아웃박스 패턴으로 결제 DB 커밋과 지급 이벤트를 원자화, 지급 소비는 멱등.
- 랭킹: AP로 두고 주기적 수렴(약간의 지연 허용).
흔한 오답·함정
- "CAP에서 셋 다 포기 못 하니 하나 고른다" 식의 단순화 — 정확히는 분단 시 C/A 중 택. 평상시엔 둘 다 가능.
- 게임 전체에 강한 일관성 강제 → 지연·가용성 폭탄. 데이터별로 차등 적용.
- 2PC를 일반 트랜잭션처럼 남용 → 블로킹·장애 확산. 대부분 Saga가 현실적.
꼬리질문 대비
- Q. 아웃박스 패턴이란? 비즈니스 DB 트랜잭션 안에서 "보낼 이벤트"를 같은 DB의 outbox 테이블에 함께 기록 → 별도 릴레이가 읽어 큐로 발행. DB 커밋과 발행의 원자성을 확보.
- Q. Saga의 보상이 또 실패하면? 재시도 + 수동 개입 큐(DLQ) + 멱등 보상. 보상도 멱등이어야 함.
- Q. 강한 일관성을 분산에서 구현하는 합의 알고리즘? Raft/Paxos(리더 선출·로그 복제). etcd/ZooKeeper가 이를 제공.