256. 결과적 일관성 (Eventual Consistency)

핵심 인사이트 (3줄 요약)

  1. 본질: 결과적 일관성은 분산 시스템에서 쓰기 연산 후 모든 복제본이 궁극적으로同一해지는 일관성 모델로, 짧은 시간 동안 복제본 간 데이터 불일치가 발생할 수 있다.
  2. 가치: AP 시스템에서 가용성과 Partition Tolerance를 유지하면서 데이터를 복제할 수 있게 해주는 현실적 일관성 모델이다.
  3. 융합: CAP 정리, BASE 속성, 복제 전략, Vector Clock, MVCC와 밀접하게 연관되며, NoSQL 및 분산 캐시에서 기본으로 사용된다.

Ⅰ. 개요 및 필요성 (Context & Necessity)

개념 정의

결과적 일관성(Eventual Consistency)은 Werner Vogels가 2008년 Amazon CTO로서 제안한 일관성 모델이다. 이 모델에서는 쓰기 연산이 성공적으로 반환된 후, 복제 메커니즘을 통해 모든 복제본이 궁극적으로 동일한 상태에 도달한다. 중요한 점은 이 과정이 즉각적이지 않으며, 일시적으로 복제본 간 데이터 불일치가 발생할 수 있다는 것이다.

필요성

강철 일관성(Strong Consistency)은 모든 노드가 동일한 시점에 동일한 데이터를 보여주지만, 이를 위해 복제가 완료될 때까지 쓰기 연산을 블로킹해야 하므로 응답 지연이 증가한다. 대규모 분산 시스템에서는 가용성과 응답 속도가 중요한 경우가 많으므로, 결과적 일관성은 강철 일관성의 대안으로 등장했다. 특히 웹 애플리케이션, SNS, IoT 센서 데이터 수집 등에서 효과적이다.

배경

결과적 일관성은 Amazon Dynamo 논문(2007)에서 처음 명확히 정의되었으며, 이후 Cassandra, DynamoDB, Riak 등 AP 시스템의 핵심 일관성 모델로 채택되었다. CAP 정리에서 AP 시스템은 네트워크 분단 시에도 가용성을 유지하므로, 일관성은 결과적으로 달성되는 수밖에 없다.

비유

결과적 일관성은 우편 시스템과 같다. 편지를 보내면 수신자가すぐに受け取るとは限らず, 数日かかる場合もあるが, 결국에는相手に届く。しかし送信者は相手の反応を待つ必要がない(非同期)。

📢 섹션 요약: 결과적 일관성은 모든 복제본이 궁극적으로 동일해지지만 일시적 불일치가 발생할 수 있는 AP 시스템의 일관성 모델이다.


Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)

결과적 일관성 동작 구조

┌─────────────────────────────────────────────────────────────────────────────┐
│                    결과적 일관성 동작 구조                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  [쓰기 요청 시]                                                               │
│                                                                             │
│       Client                                                                  │
│         │                                                                    │
│         ▼                                                                    │
│    ┌─────────────┐                                                          │
│    │   Write     │  키: "user:100", 값: "Kim"                               │
│    │  (동기 쓰기) │  → 로컬 노드에 즉시 기록                                    │
│    └──────┬──────┘                                                          │
│           │                                                                  │
│           ▼                                                                  │
│    ┌─────────────┐                                                          │
│    │ 성공 반환    │  (백그라운드에서 비동기 복제 시작)                           │
│    └─────────────┘                                                          │
│                                                                             │
│  [복제 과정: 비동기 replication]                                              │
│                                                                             │
│    Node A (writer)                                                           │
│    │ "user:100" = "Kim"                                                     │
│    │        │                                                                │
│    │        │  async replication                                            │
│    │        ▼                                                                │
│    │    Node B ◀─────────────────────────────────── Node C                  │
│    │   "user:100" = "Kim"  ...  "user:100" = "Kim" (지연)                   │
│    │                                                                         │
│    │  ※ Network Latency에 따라 복제 시간 결정                                   │
│    │  ※ 복제 완료 전 Node B, C에 읽기 요청 시 구버전 데이터 반환 가능             │
│                                                                             │
│  [불일치 시나리오]                                                            │
│                                                                             │
│    Time T0: Node A에 쓰기 완료, Node B, C에 비동기 복제 시작                      │
│    Time T1: Client가 Node B에서 읽기 → "user:100" = null (아직 미복제)           │
│    Time T2: Client가 Node C에서 읽기 → "user:100" = null                       │
│    Time T3: Client가 Node A에서 읽기 → "user:100" = "Kim" (최신)               │
│    Time T4: 모든 노드에 복제 완료 → 모든 읽기에서 "Kim" 반환                     │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

[다이어그램 해설]
결과적 일관성의 핵심은 쓰기 연산이 성공적으로 반환된 후에도 복제가 비동기로
진행된다는 점이다. 이 과정에서 복제 지연(Replication Lag)이 발생하며, 이는
네트워크 대역폭, 노드 부하, 지리적 거리 등 다양한 요인에 의해 결정된다.
문제는 복제가 완료되기 전에 읽기 요청이 발생하면 최신 데이터가 아닌 구버전의
데이터를 반환할 수 있다는 것이다. 이러한 불일치는 궁극적으로는 해소되지만,
일시적이므로 애플리케이션 설계 시 이를 감안해야 한다.

일관성 수준 스펙트럼

┌─────────────────────────────────────────────────────────────────────────────┐
│                    일관성 수준 스펙트럼 (강함 → 약함)                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  강철 일관성 ────────────────────────────────▶ 결과적 일관성                 │
│                                                                             │
│  Linearizability                                                             │
│  ├── 모든 연산이 글로벌 시계 순서로 실행                                       │
│  ├── 읽기가 항상 최신 쓰기 결과 반영                                          │
│  └── 가장 강한 일관성, 가장 높은 지연                                          │
│                                                                             │
│  Sequential Consistency                                                      │
│  ├── 모든 노드가 동일한 연산 순서를 관찰                                       │
│  ├── 시간 순서는 보장하지 않음                                                │
│  └── 예: Zookeeper                                                           │
│                                                                             │
│  Causal Consistency                                                          │
│  ├── 원인과 결과의 관계가 올바르게 보존                                        │
│  ├── 병렬 연산은 순서 보장 불가                                               │
│  └── 예: MongoDB (causal consistent sessions)                               │
│                                                                             │
│  eventual Consistency                                                        │
│  ├── 쓰기 후 궁극적으로 모든 복제본이 동일해짐                                  │
│  ├── 불일치 창(Staleness Window)이 존재                                      │
│  └── 예: Cassandra, DynamoDB, S3                                            │
│                                                                             │
│  monotonic Consistency                                                       │
│  ├── 읽기가 이전 읽기보다 오래된 데이터를 반환하지 않음                         │
│  ├── 쓰기는 나중에 반영                                                       │
│  └── eventual의 특별한 형태                                                   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐  │
│  │                      일관성 수준 비교                                   │  │
│  │  ┌─────────────────┬────────────────┬────────────────┐              │  │
│  │  │     수준        │   지연 시간     │   불일치 창    │              │  │
│  │  ├─────────────────┼────────────────┼────────────────┤              │  │
│  │  │ Linearizability │    가장 높음    │      없음     │              │  │
│  │  │ Sequential      │     높음       │      없음     │              │  │
│  │  │ Causal          │     중간       │   작음        │              │  │
│  │  │ Eventual        │     낮음       │   가변적      │              │  │
│  │  │ Monotonic       │     낮음       │   제한적      │              │  │
│  │  └─────────────────┴────────────────┴────────────────┘              │  │
│  └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

[다이어그램 해설] 일관성 수준은 강철 일관성에서 결과적 일관성까지 연속적인 스펙트럼으로 표현할 수 있다. 강철 일관성으로 갈수록 읽기 연산의 응답 지연이 증가하지만 불일치가 발생하지 않으며, 결과적 일관성으로 갈수록 응답 지연이 감소하지만 불일치 창(Staleness Window)이 발생한다. 애플리케이션의 요구사항에 따라 적절한 일관성 수준을 선택해야 한다. 예를 들어 금융 거래에서는 Linearizability가 필수이지만, SNS 포스트 조회에서는 Eventual consistency로도 충분하다.

📢 섹션 요약: 일관성 수준은 강철에서 결과적까지 연속적 스펙트럼이며, 일관성이 강할수록 지연이 증가하고 일관성이 약할수록 지연이 감소한다.


Ⅲ. 구현 및 실무 응용 (Implementation & Practice)

Cassandra의 결과적 일관성 구현

-- Cassandra에서의 읽기/쓰기 동작 (결과적 일관성)

-- 키스페이스 생성
CREATE KEYSPACE mykeyspace
WITH REPLICATION = {'class': 'NetworkTopologyStrategy', 'dc1': 3};

-- 쓰기: 즉시 반환, 백그라운드 복제
INSERT INTO users (id, name, email) VALUES (1, 'Kim', 'kim@test.com')
USING CONSISTENCY QUORUM;
-- • 로컬 노드에 먼저 기록 (CommitLog, Memtable)
-- • 성공 반환 (복제는 백그라운드에서 진행)
-- • 다른 노드에 복제 전 읽기 시 구버전 데이터 반환 가능

-- 읽기: 복제본 중 가장 최근 데이터 반환
SELECT * FROM users WHERE id = 1 USING CONSISTENCY QUORUM;
-- • QUORUM 수(여기서는 2)의 노드에서 읽기
-- • 각 노드의 Timestamp 비교하여 최신 데이터 선택
-- • 복제 지연이 있는 경우 구버전 데이터 반환 가능

-- Consistency Level에 따른 동작
-- • ALL: 모든 노드에서 읽기 → 강철 일관성, 지연 높음
-- • QUORUM: 과반 노드에서 읽기 → 균형점
-- • ONE: 가장 가까운 노드에서 읽기 → 지연 가장 낮음, 불일치 가능성 높음

DynamoDB의 결과적 일관성 읽기

# AWS DynamoDB에서의 Eventually vs Strongly Consistent 읽기

import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Users')

# Eventually Consistent 읽기 (기본값)
response = table.get_item(Key={'user_id': '123'})
# - 가장 가까운 복제본에서 읽기
# - 지연 시간 최소화
# - 최신 데이터가 아닐 수 있음 (Staleness 가능)

# Strongly Consistent 읽기
response = table.get_item(Key={'user_id': '123'}, ConsistentRead=True)
# - 모든 복제본이 동기화된 후 반환
# - 지연 시간 증가
# - 항상 최신 데이터

# 쓰기 후 읽기 시뮬레이션
table.put_item(Item={'user_id': '123', 'name': 'Kim'})
# - 쓰기 성공 반환
# - 백그라운드 복제 시작

# 바로 읽으면 (Eventually Consistent)
response = table.get_item(Key={'user_id': '123'})  # Kim이 아닐 수 있음

# 나중에 읽으면 (Eventually Consistent)
# → Eventually consistent에 의해 결국 Kim 반환

결과적 일관성 감수를 위한 설계 패턴

┌─────────────────────────────────────────────────────────────────────────────┐
│                    결과적 일관성 감수를 위한 설계 패턴                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  패턴 1: 마지막 쓰기 wins (Last Writer Wins)                                │
│  ─────────────────────────────────────────────────────────────────────      │
│  • 각 쓰기에 타임스탬프 부여                                                  │
│  • 읽기 시 가장 최신 타임스탬프의 값 반환                                      │
│  • 단순하지만 최근 쓰기가 earlier 쓰기를 덮어쓸 수 있음                        │
│  • 예: Cassandra, DynamoDB                                                  │
│                                                                             │
│  패턴 2: 버전 번호 방식                                                       │
│  ─────────────────────────────────────────────────────────────────────      │
│  • 각 데이터에 버전 번호 부여                                                  │
│  • 읽기 시 가장 높은 버전의 데이터 반환                                        │
│  • 버전 충돌 감지 가능                                                        │
│  • 예: MongoDB                                                               │
│                                                                             │
│  패턴 3: 애플리케이션 수준 병합                                               │
│  ─────────────────────────────────────────────────────────────────────      │
│  • 복제 충돌을 애플리케이션에서 해결                                           │
│  • 비즈니스 로직에 맞는 해결 방식 구현                                         │
│  • 복잡하지만 정확한 제어 가능                                                 │
│  • 예: Riak (Custom conflict resolution)                                     │
│                                                                             │
│  패턴 4: 읽기 복구 (Read Repair)                                            │
│  ─────────────────────────────────────────────────────────────────────      │
│  • 읽기 시 오래된 복제본을 자동으로 업데이트                                     │
│  •_background에서 실행                                                        │
│  • 데이터 품질 향상                                                          │
│  • 예: Cassandra, DynamoDB                                                  │
│                                                                             │
│  패턴 5: 안티엔트로피 복구 (Anti-Entropy Repair)                            │
│  ─────────────────────────────────────────────────────────────────────      │
│  • 주기적으로 모든 복제본을 비교하여 불일치 해결                                │
│  • Merkle Tree 사용하여 차분 발견                                              │
│  • 시스템 전체적으로 일관성 유지                                               │
│  • 예: Cassandra (nodetool repair)                                          │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

📢 섹션 요약: 결과적 일관성 환경에서는 Last Writer Wins, 버전 관리, 읽기 복구 등 다양한 충돌 해소 전략을 사용하여 불일치를 관리해야 한다.


Ⅳ. 품질 관리 및 테스트 (Quality & Testing)

결과적 일관성 테스트

┌─────────────────────────────────────────────────────────────────────────────┐
│                    결과적 일관성 품질 테스트 항목                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  [Staleness 측정]                                                            │
│  ─────────────────                                                            │
│  • 쓰기 후 읽기까지의 불일치 창(Staleness Window) 측정                        │
│  • 다양한 네트워크 조건에서 복제 지연 시간 측정                                 │
│  • 노드 부하에 따른 복제 지연 변화 분석                                         │
│                                                                             │
│  [충돌 감지 및 해소 테스트]                                                   │
│  ──────────────────────────                                                  │
│  • 동시 쓰기 시 충돌 발생 빈도 측정                                            │
│  • 충돌 해소 방식 (LWW, 版本号, 애플리케이션) 동작 확인                        │
│  • 충돌로 인한 데이터 손실 여부 확인                                           │
│                                                                             │
│  [읽기 일관성 테스트]                                                        │
│  ───────────────────                                                         │
│  • 동일 키에 대한 반복 읽기에서 반환 값 변화 분석                               │
│  •monotonic read 보장 여부 확인                                               │
│  • 읽기 복구(Read Repair) 동작 확인                                           │
│                                                                             │
│  [성능 테스트]                                                               │
│  ─────────────                                                               │
│  • Consistency Level별 응답 시간 비교                                          │
│  • 시스템 부하 시 복제 지연 증가 분석                                           │
│  • 확장성 테스트: 노드 추가 시 일관성 동작 변화                                 │
│                                                                             │
│  [장애 복구 테스트]                                                           │
│  ──────────────────                                                           │
│  • 노드 장애 시 복제 재구성 동작 확인                                          │
│  • 장애 복구 후 일관성 복구 시간 측정                                          │
│  • 데이터 손실 여부 확인                                                       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

📢 섹션 요약: 결과적 일관성 테스트는 Staleness 측정, 충돌 해소 검증, 성능 및 장애 복구 테스트를 포함해야 하며, 실제 환경에서의 동작을 사전에 검증해야 한다.


적응적 일관성

최근에는 애플리케이션의 要求에 따라 일관성 수준을 동적으로 조절하는 적응적 일관성(Adaptive Consistency) 기술이 발전하고 있다. 예를 들어付费고객에게는 강철 일관성을, 무료사용자에게는 결과적 일관성을 제공하는 것이 대표적이다. Amazon DynamoDB Streams나 Azure Cosmos DB의 multi-region 은 이러한 적응적 일관성을 지원한다.

CRDT의 활용

Conflict-free Replicated Data Types (CRDT)는 결과적 일관성 환경에서 충돌 없이 자동으로 병합 가능한 자료구조이다. Counters, Sets, Registers, Maps 등의 타입이 있으며, 분산 시스템에서 결과적 일관성을 보장하면서도 충돌을 자동으로 해결할 수 있다. Riak, Redis CRDT 모듈 등에서 활용된다.

결론

결과적 일관성은 AP 시스템의 핵심 일관성 모델로서, 강철 일관성의 대안으로 대규모 분산 시스템에서 효과적으로 활용된다. 그러나 일시적 불일치가 발생할 수 있다는 특성을 이해하고, 애플리케이션에서 이를 감수하거나 적절히 처리해야 한다. 결과적 일관성에서도 Last Writer Wins, 버전 관리, 읽기 복구 등의 메커니즘을 통해 데이터 품질을 관리할 수 있다.

📢 섹션 요약: 결과적 일관성은 AP 시스템의 핵심 모델로, 강철 일관성의 대안이지만 일시적 불일치를 감수해야 하며, 충돌 해소 전략과 모니터링을 통해 데이터 품질을 관리해야 한다.


핵심 인사이트 ASCII 다이어그램 (Concept Map)

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Eventual Consistency Concept Map                          │
│                                                                             │
│              ┌───────────────────────┐                                      │
│              │  결과적 일관성         │                                      │
│              │ (Eventual Consistency) │                                      │
│              └───────────┬───────────┘                                      │
│                          │                                                  │
│       ┌──────────────────┼──────────────────┐                               │
│       ▼                  ▼                  ▼                               │
│  ┌─────────┐       ┌─────────┐       ┌─────────┐                           │
│  │ 쓰기 후  │       │ 불일치  │       │ 충돌    │                           │
│  │ 비동기   │       │ 창(Staleness)│    │ 해소   │                           │
│  │ 복제     │       │ Window) │       │ (LWW 등)│                           │
│  └─────────┘       └─────────┘       └─────────┘                           │
│       │                  │                  │                              │
│       ▼                  ▼                  ▼                              │
│  ┌─────────────────────────────────────────────────────┐                    │
│  │              관련 일관성 모델                        │                    │
│  │  Linearizability → Sequential → Causal → Monotonic  │                    │
│  │                                        → Eventual   │                    │
│  └─────────────────────────────────────────────────────┘                    │
│                                                                             │
│  관련 기술: CRDT, Read Repair, Anti-Entropy, Vector Clock, MVCC             │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

참고

  • 결과적 일관성은 쓰기 연산 후 궁극적으로 모든 복제본이 동일해지는 일관성 모델이다.
  • AP 시스템의 핵심 일관성 모델로, Cassandra, DynamoDB, S3 등에서 사용된다.
  • 일시적 불일치가 발생할 수 있으므로 애플리케이션 설계 시 이를 감안해야 한다.
  • 충돌 해소 전략(Last Writer Wins, 버전 관리 등)을 통해 데이터 품질을 관리해야 한다.