데이터 일관성 패턴 (Data Consistency Patterns)
데이터 일관성 패턴 (Data Consistency Patterns)¶
난이도: ⭐⭐⭐⭐
개요¶
분산 시스템에서 데이터 일관성은 가장 도전적인 문제 중 하나입니다. 이 장에서는 Strong Consistency와 Eventual Consistency의 트레이드오프, 읽기 일관성 패턴, 분산 트랜잭션의 한계, 그리고 Saga 패턴을 학습합니다.
목차¶
1. 일관성 모델 개요¶
CAP 정리 복습¶
┌─────────────────────────────────────────────────────────────┐
│ CAP 정리 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Consistency (C) │
│ /\ │
│ / \ │
│ / \ │
│ / CP \ │
│ / \ │
│ /──────────\ │
│ Availability (A) Partition Tolerance (P) │
│ \ AP / │
│ \ / │
│ \──────/ │
│ │
│ 네트워크 파티션 발생 시: │
│ - CP 선택: 일관성 유지, 가용성 포기 │
│ - AP 선택: 가용성 유지, 일관성 포기 (Eventual) │
└─────────────────────────────────────────────────────────────┘
일관성 스펙트럼¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 일관성 스펙트럼 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Strong Eventual │
│ Consistency ◄────────────────────────► Consistency │
│ │
│ ├──────────┬──────────┬──────────┬──────────┬──────────┤ │
│ │ │ │ │ │ │ │
│ Lineariz- Sequential Causal Monotonic Eventual │
│ ability Consistency Reads Consistency │
│ │
│ ◄───────── 강한 일관성 ─────────►◄───── 약한 일관성 ────► │
│ ◄─────── 낮은 가용성/성능 ──────►◄── 높은 가용성/성능 ──► │
│ │
└─────────────────────────────────────────────────────────────────────────┘
2. Strong vs Eventual Consistency¶
Strong Consistency (강한 일관성)¶
모든 읽기가 가장 최근 쓰기 결과를 반환합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Strong Consistency │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 시간 ──────────────────────────────────────────────────────► │
│ │
│ Client A: ──── Write(X=5) ─────────────────────────────► │
│ │ │
│ ▼ │
│ Primary: ════════[X=5]════════════════════════════════► │
│ │ │
│ │ 동기 복제 │
│ │ (쓰기 완료 전 복제 완료) │
│ ▼ │
│ Replica: ════════[X=5]════════════════════════════════► │
│ │ │
│ ▼ │
│ Client B: ──────── Read() ─────── returns X=5 ────────► │
│ │
│ 특징: │
│ - 모든 노드가 같은 데이터를 봄 │
│ - 쓰기 지연 증가 │
│ - 가용성 감소 (복제본 장애 시) │
└─────────────────────────────────────────────────────────────────────────┘
Eventual Consistency (최종 일관성)¶
충분한 시간이 지나면 모든 읽기가 같은 값을 반환합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Eventual Consistency │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 시간 ──────────────────────────────────────────────────────► │
│ │
│ Client A: ──── Write(X=5) ─────────────────────────────► │
│ │ │
│ ▼ │
│ Primary: ════════[X=5]════════════════════════════════► │
│ │ │
│ │ 비동기 복제 │
│ │ (쓰기 즉시 완료, 복제는 나중에) │
│ ▼ │
│ Replica: ═══[X=0]════════[X=5]════════════════════════► │
│ │ │ │
│ │ 복제 지연 │ │
│ ▼ ▼ │
│ Client B: ─── Read()=0 ──── Read()=5 ─────────────────► │
│ (stale) (current) │
│ │
│ 특징: │
│ - 일시적 불일치 허용 │
│ - 쓰기 지연 감소 │
│ - 높은 가용성 │
└─────────────────────────────────────────────────────────────────────────┘
트레이드오프 비교¶
| 특성 | Strong Consistency | Eventual Consistency |
|---|---|---|
| 읽기 일관성 | 항상 최신 | 일시적 지연 |
| 쓰기 지연 | 높음 | 낮음 |
| 가용성 | 낮음 | 높음 |
| 구현 복잡도 | 높음 | 낮음 |
| 적합한 사례 | 금융, 재고 | SNS, 좋아요 수 |
사용 사례별 선택¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 사용 사례별 일관성 선택 │
├───────────────────────────────┬─────────────────────────────────────────┤
│ Strong Consistency 필요 │ Eventual Consistency 적합 │
├───────────────────────────────┼─────────────────────────────────────────┤
│ - 은행 계좌 잔액 │ - SNS 타임라인 │
│ - 재고 수량 (중복 판매 방지) │ - 좋아요/팔로워 수 │
│ - 예약 시스템 │ - 검색 인덱스 │
│ - 결제 처리 │ - 로그 수집 │
│ - 사용자 인증 상태 │ - 조회수 카운터 │
│ - 분산 락 │ - 추천 시스템 │
└───────────────────────────────┴─────────────────────────────────────────┘
3. 읽기 일관성 패턴¶
Read-Your-Writes (자신의 쓰기 읽기)¶
사용자가 자신이 쓴 데이터를 항상 읽을 수 있도록 보장합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Read-Your-Writes │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 문제 상황: │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ User A │ │ Primary │ │ Replica │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ │──Write(name=Bob)──►│ │ │
│ │◄── Success ────────│ │ │
│ │ │── async replicate─►│ │
│ │──Read(name)────────────────────────────►│ (아직 복제 안됨) │
│ │◄─────────────────── name=Alice ─────────│ │
│ │ │ │
│ "내가 방금 Bob으로 바꿨는데 왜 Alice지?" │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 해결 방법 1: Primary에서 읽기 │
│ ┌──────────┐ ┌──────────┐ │
│ │ User A │ │ Primary │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ │──Write(name=Bob)──►│ │
│ │◄── Success ────────│ │
│ │──Read(name)───────►│ ← 자신의 쓰기 후에는 Primary에서 읽기 │
│ │◄─── name=Bob ──────│ │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 해결 방법 2: 타임스탬프 기반 │
│ │
│ - 쓰기 시 타임스탬프 T 기록 │
│ - 읽기 시 T 이후의 데이터가 있는 복제본에서만 읽기 │
│ - 복제본의 replication_timestamp >= T인 경우만 사용 │
│ │
│ Write Response: { success: true, timestamp: T1 } │
│ Read Request: { key: "name", min_timestamp: T1 } │
│ → T1 이후 업데이트된 복제본에서만 읽기 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
# Read-Your-Writes 구현 예시
class ReadYourWritesClient:
def __init__(self, primary, replicas):
self.primary = primary
self.replicas = replicas
self.last_write_timestamp = {} # key -> timestamp
def write(self, key, value):
timestamp = self.primary.write(key, value)
self.last_write_timestamp[key] = timestamp
return timestamp
def read(self, key):
if key in self.last_write_timestamp:
# 최근 쓴 키는 Primary에서 읽기
return self.primary.read(key)
else:
# 쓰지 않은 키는 Replica에서 읽기
return self.select_replica().read(key)
Monotonic Reads (단조 읽기)¶
한번 읽은 값보다 오래된 값을 읽지 않도록 보장합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Monotonic Reads │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 문제 상황 (Monotonic Reads 위반): │
│ │
│ 시간 ──────────────────────────────────────────────────────► │
│ │
│ Replica 1: [v1]───────[v2]───────[v3]────────────────────► │
│ Replica 2: [v1]───────────────────────[v2]───────────────► │
│ │
│ User: Read@R1=v2 Read@R2=v1 Read@R1=v3 │
│ │ │ │
│ └─────────┘ │
│ "시간이 거꾸로 간 것 같은 경험" │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 해결 방법: Sticky Session │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ User A │─────────│ Replica 1│ │
│ └──────────┘ 고정 └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ User B │─────────│ Replica 2│ │
│ └──────────┘ 고정 └──────────┘ │
│ │
│ - 같은 사용자는 항상 같은 복제본에서 읽기 │
│ - 해당 복제본이 다운되면 다른 복제본으로 전환 │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 해결 방법: 버전 기반 │
│ │
│ Read Response: { value: "v2", version: 42 } │
│ Next Read Request: { key: "data", min_version: 42 } │
│ → version >= 42인 복제본에서만 읽기 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Monotonic Writes (단조 쓰기)¶
동일 세션의 쓰기가 순서대로 적용되도록 보장합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Monotonic Writes │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 문제 상황: │
│ │
│ User: Write(X=1) → Write(X=2) → Write(X=3) │
│ │
│ 네트워크 지연으로 인해: │
│ Replica 수신 순서: X=2 → X=3 → X=1 │
│ 최종 결과: X=1 (의도와 다름!) │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 해결 방법: 버전/타임스탬프 기반 │
│ │
│ Write(X=1, ts=100) → Write(X=2, ts=101) → Write(X=3, ts=102) │
│ │
│ 수신 순서: ts=101 → ts=102 → ts=100 │
│ 적용: X=2 적용 → X=3 적용 → X=1 무시 (ts=100 < 현재 ts=102) │
│ 최종 결과: X=3 (정확!) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
4. 분산 트랜잭션과 2PC¶
Two-Phase Commit (2PC)¶
분산 트랜잭션의 원자성을 보장하는 프로토콜입니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Two-Phase Commit (2PC) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Phase 1: Prepare (투표 단계) │
│ ┌─────────────┐ │
│ │ Coordinator │ │
│ └──────┬──────┘ │
│ │ │
│ │─── PREPARE ───►┌────────────┐ │
│ │ │Participant1│───► 트랜잭션 준비 │
│ │◄── VOTE YES ───└────────────┘ (락 획득, 로그 기록) │
│ │ │
│ │─── PREPARE ───►┌────────────┐ │
│ │ │Participant2│───► 트랜잭션 준비 │
│ │◄── VOTE YES ───└────────────┘ │
│ │ │
│ Phase 2: Commit (결정 단계) │
│ │ │
│ │─── COMMIT ────►┌────────────┐ │
│ │ │Participant1│───► 커밋 수행 │
│ │◄─── ACK ───────└────────────┘ │
│ │ │
│ │─── COMMIT ────►┌────────────┐ │
│ │ │Participant2│───► 커밋 수행 │
│ │◄─── ACK ───────└────────────┘ │
│ │ │
│ ▼ │
│ Transaction Complete │
│ │
└─────────────────────────────────────────────────────────────────────────┘
2PC 실패 시나리오¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 2PC 실패 시나리오 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 시나리오 1: Participant가 NO 투표 │
│ ┌─────────────┐ │
│ │ Coordinator │ │
│ └──────┬──────┘ │
│ │─── PREPARE ───►│Participant1│◄── VOTE YES │
│ │─── PREPARE ───►│Participant2│◄── VOTE NO (실패) │
│ │ │
│ │─── ROLLBACK ──►│Participant1│ │
│ │─── ROLLBACK ──►│Participant2│ │
│ ▼ │
│ Transaction Aborted │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 시나리오 2: Coordinator 장애 (Blocking 문제) │
│ │
│ ┌─────────────┐ │
│ │ Coordinator │──X (장애) │
│ └──────┬──────┘ │
│ │─── PREPARE ───►│Participant1│◄── VOTE YES (대기 중...) │
│ │─── PREPARE ───►│Participant2│◄── VOTE YES (대기 중...) │
│ │ │
│ X Coordinator 다운! │
│ │
│ │Participant1│: "Commit? Rollback? 결정 불가..." │
│ │Participant2│: "리소스 락이 계속 유지됨..." │
│ │
│ ─────────────────────────────────────────────────────────────────── │
│ 이것이 2PC의 가장 큰 문제: BLOCKING │
│ Coordinator 복구 전까지 Participant들이 무한 대기 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
2PC의 한계¶
| 한계 | 설명 |
|---|---|
| Blocking | Coordinator 장애 시 전체 시스템 블로킹 |
| 성능 | 네트워크 왕복 2회, 모든 참여자 대기 |
| 가용성 | 한 참여자라도 실패하면 전체 롤백 |
| 확장성 | 참여자 증가 시 성능 급격히 저하 |
3PC (Three-Phase Commit)¶
2PC의 블로킹 문제를 완화하려는 시도:
┌─────────────────────────────────────────────────────────────────────────┐
│ 3PC vs 2PC │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 2PC: 3PC: │
│ 1. Prepare 1. CanCommit (투표) │
│ 2. Commit/Rollback 2. PreCommit (준비 확인) │
│ 3. DoCommit (실제 커밋) │
│ │
│ 3PC 장점: │
│ - PreCommit 단계에서 참여자들이 상태 공유 │
│ - Coordinator 장애 시에도 참여자간 합의 가능 │
│ │
│ 3PC 한계: │
│ - 네트워크 파티션 시 여전히 불일치 가능 │
│ - 복잡도 증가, 실무에서 잘 사용 안함 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
5. Saga 패턴¶
2PC의 한계를 극복하기 위한 분산 트랜잭션 패턴입니다.
Saga 기본 개념¶
┌─────────────────────────────────────────────────────────────────────────┐
│ Saga 패턴 개요 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 2PC: 하나의 큰 트랜잭션으로 원자적 처리 │
│ [─────────── 전체 트랜잭션 ───────────] │
│ 실패 시 전체 롤백 (락 유지) │
│ │
│ Saga: 여러 로컬 트랜잭션의 시퀀스 │
│ [T1] → [T2] → [T3] → [T4] │
│ 실패 시 보상 트랜잭션 실행 │
│ [T1] → [T2] → [T3-실패] → [C2] → [C1] │
│ 보상 트랜잭션 │
│ │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ 예시: 여행 예약 Saga │
│ │
│ 정상 흐름: │
│ [항공권 예약] → [호텔 예약] → [렌터카 예약] → [결제] │
│ T1 T2 T3 T4 │
│ │
│ T3 실패 시: │
│ [항공권 예약] → [호텔 예약] → [렌터카-실패] → [호텔 취소] → [항공 취소]│
│ T1 T2 T3 C2 C1 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Choreography (안무)¶
각 서비스가 이벤트를 발행하고 구독하여 자율적으로 동작합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Choreography Saga │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Order │ │ Payment │ │ Stock │ │Shipping │ │
│ │ Service │ │ Service │ │ Service │ │ Service │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ ═════╪══════════════╪══════════════╪══════════════╪═══ Event Bus │
│ │ │ │ │ │
│ 1.OrderCreated │ │ │ │
│ ─────┼─────────────►│ │ │ │
│ │ 2.PaymentCompleted │ │ │
│ │ ─────┼─────────────►│ │ │
│ │ │ 3.StockReserved │ │
│ │ │ ───────┼─────────────►│ │
│ │ │ │ 4.ShippingScheduled │
│ │ │ │ ──────────┼────► │
│ │◄─────────────┼──────────────┼──────────────┼──── 5.OrderComplete│
│ │ │ │ │ │
│ ───────────────────────────────────────────────────────────────────── │
│ 실패 시 보상 이벤트: │
│ │
│ 1.OrderCreated ──► 2.PaymentCompleted ──► 3.StockFailed! │
│ │ │
│ PaymentRefunded ◄──────────┘ │
│ │ │
│ OrderCancelled ◄───┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Choreography 장단점¶
| 장점 | 단점 |
|---|---|
| 느슨한 결합 | 전체 흐름 파악 어려움 |
| 단일 장애점 없음 | 순환 의존성 위험 |
| 서비스 독립적 확장 | 디버깅 복잡 |
| 간단한 구현 | 테스트 어려움 |
Orchestration (오케스트레이션)¶
중앙의 Orchestrator가 전체 흐름을 제어합니다.
┌─────────────────────────────────────────────────────────────────────────┐
│ Orchestration Saga │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ Orchestrator │ │
│ │ (Saga Manager) │ │
│ └────────┬────────┘ │
│ │ │
│ ┌─────────────────────┼─────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Order │ │ Payment │ │ Stock │ │
│ │ Service │ │ Service │ │ Service │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 정상 흐름: │
│ │
│ Orchestrator │
│ │ │
│ │──── 1. CreateOrder ────►│Order│ │
│ │◄─── OrderCreated ───────│ │ │
│ │ │
│ │──── 2. ProcessPayment ─►│Payment│ │
│ │◄─── PaymentDone ────────│ │ │
│ │ │
│ │──── 3. ReserveStock ───►│Stock│ │
│ │◄─── StockReserved ──────│ │ │
│ │ │
│ │──── 4. CompleteOrder ──►│Order│ │
│ ▼ │
│ Saga Complete │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ 실패 시 보상: │
│ │
│ Orchestrator │
│ │ │
│ │──── 1. CreateOrder ────►│Order│ ✓ │
│ │──── 2. ProcessPayment ─►│Payment│ ✓ │
│ │──── 3. ReserveStock ───►│Stock│ ✗ (실패!) │
│ │ │
│ │──── 4. RefundPayment ──►│Payment│ (보상) │
│ │──── 5. CancelOrder ────►│Order│ (보상) │
│ ▼ │
│ Saga Rolled Back │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Orchestration 장단점¶
| 장점 | 단점 |
|---|---|
| 중앙 집중 흐름 관리 | 단일 장애점 |
| 명확한 워크플로우 | Orchestrator 복잡도 증가 |
| 디버깅/모니터링 용이 | 결합도 증가 |
| 테스트 용이 | Orchestrator 확장성 |
Saga 패턴 비교¶
┌─────────────────────────────────────────────────────────────────────────┐
│ Choreography vs Orchestration 선택 기준 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Choreography 선택: │
│ - 서비스 수가 적을 때 (2-4개) │
│ - 단순한 워크플로우 │
│ - 서비스 독립성이 중요할 때 │
│ - 팀 간 강한 결합을 피하고 싶을 때 │
│ │
│ Orchestration 선택: │
│ - 복잡한 비즈니스 로직 │
│ - 서비스 수가 많을 때 (5개 이상) │
│ - 명확한 에러 처리가 필요할 때 │
│ - 워크플로우 가시성이 중요할 때 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Saga 구현 예시 (Orchestration)¶
class OrderSaga:
"""주문 Saga Orchestrator"""
def __init__(self, order_id):
self.order_id = order_id
self.state = "STARTED"
self.compensations = [] # 보상 트랜잭션 스택
def execute(self):
try:
# Step 1: 주문 생성
self.create_order()
self.compensations.append(self.cancel_order)
# Step 2: 결제 처리
self.process_payment()
self.compensations.append(self.refund_payment)
# Step 3: 재고 차감
self.reserve_stock()
self.compensations.append(self.release_stock)
# Step 4: 배송 예약
self.schedule_shipping()
self.state = "COMPLETED"
except SagaException as e:
self.compensate()
self.state = "COMPENSATED"
raise
def compensate(self):
"""역순으로 보상 트랜잭션 실행"""
while self.compensations:
compensation = self.compensations.pop()
try:
compensation()
except Exception as e:
# 보상 실패 로깅, 재시도 큐에 등록
log_compensation_failure(self.order_id, compensation, e)
def create_order(self):
# Order Service 호출
pass
def cancel_order(self):
# Order Service - 주문 취소
pass
# ... 다른 메서드들
6. 실전 적용 가이드¶
일관성 패턴 선택 체크리스트¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 일관성 패턴 선택 가이드 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 질문 1: 데이터 불일치가 비즈니스에 미치는 영향은? │
│ ├── 치명적 (금전적 손실, 법적 문제) ──► Strong Consistency │
│ └── 허용 가능 (잠시 오래된 정보) ──► Eventual Consistency │
│ │
│ 질문 2: 시스템의 주요 요구사항은? │
│ ├── 낮은 지연시간 ──► Eventual Consistency │
│ └── 데이터 정확성 ──► Strong Consistency │
│ │
│ 질문 3: 장애 시 시스템 동작은? │
│ ├── 일부 기능 중단 허용 ──► Strong Consistency (CP) │
│ └── 항상 응답 필요 ──► Eventual Consistency (AP) │
│ │
│ 질문 4: 읽기/쓰기 비율은? │
│ ├── 읽기 집중 (90%+) ──► Eventual + Read Replica │
│ └── 쓰기 집중 ──► Careful! 복제 지연 고려 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
하이브리드 접근¶
┌─────────────────────────────────────────────────────────────────────────┐
│ 하이브리드 일관성 전략 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 같은 시스템 내에서도 데이터별로 다른 일관성 수준 적용 │
│ │
│ 예: 이커머스 시스템 │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 데이터 유형 │ 일관성 수준 │ 이유 │ │
│ ├──────────────────────┼───────────────────┼───────────────────┤ │
│ │ 재고 수량 │ Strong │ 과잉판매 방지 │ │
│ │ 결제 상태 │ Strong │ 금전 정확성 │ │
│ │ 상품 리뷰 │ Eventual │ 즉시 반영 불필요 │ │
│ │ 조회수 │ Eventual │ 정확성 덜 중요 │ │
│ │ 장바구니 │ Session │ 사용자별 일관성 │ │
│ │ 추천 상품 │ Eventual │ 실시간 불필요 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
7. 연습 문제¶
연습 1: 일관성 요구사항 분석¶
다음 시나리오에서 적절한 일관성 모델을 선택하고 이유를 설명하세요:
- 은행 계좌 잔액
- Twitter 팔로워 수
- 온라인 게임 랭킹
- 항공권 좌석 예약
- 뉴스 기사 조회수
연습 2: Saga 설계¶
온라인 쇼핑몰의 주문 프로세스를 Saga 패턴으로 설계하세요: - 주문 생성, 재고 확인, 결제, 배송 예약 단계 포함 - 각 단계의 보상 트랜잭션 정의 - Choreography와 Orchestration 두 가지 버전으로 설계
연습 3: 읽기 일관성 구현¶
Read-Your-Writes를 보장하는 클라이언트 라이브러리를 설계하세요: - 쓰기 후 읽기 시 최신 데이터 반환 보장 - 타임스탬프 기반 접근법 사용 - 캐싱 전략 포함
다음 단계¶
11_Message_Queue_Basics.md에서 비동기 통신의 기반이 되는 메시지 큐에 대해 배워봅시다!
참고 자료¶
- "Designing Data-Intensive Applications" - Martin Kleppmann
- "Microservices Patterns" - Chris Richardson
- Google Cloud Spanner: TrueTime and External Consistency
- AWS: Building Distributed Locks with DynamoDB
- "Sagas" - Hector Garcia-Molina, Kenneth Salem (1987)