데이터 일관성 패턴 (Data Consistency Patterns)

데이터 일관성 패턴 (Data Consistency Patterns)

난이도: ⭐⭐⭐⭐

개요

분산 시스템에서 데이터 일관성은 가장 도전적인 문제 중 하나입니다. 이 장에서는 Strong Consistency와 Eventual Consistency의 트레이드오프, 읽기 일관성 패턴, 분산 트랜잭션의 한계, 그리고 Saga 패턴을 학습합니다.


목차

  1. 일관성 모델 개요
  2. Strong vs Eventual Consistency
  3. 읽기 일관성 패턴
  4. 분산 트랜잭션과 2PC
  5. Saga 패턴
  6. 실전 적용 가이드
  7. 연습 문제

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: 일관성 요구사항 분석

다음 시나리오에서 적절한 일관성 모델을 선택하고 이유를 설명하세요:

  1. 은행 계좌 잔액
  2. Twitter 팔로워 수
  3. 온라인 게임 랭킹
  4. 항공권 좌석 예약
  5. 뉴스 기사 조회수

연습 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)
to navigate between lessons