











핵심 개념
- 복제: 네트워크로 연결된 여러 머신에 동일한 데이터의 복사본을 유지하는 것
- 목적: 고가용성, 지연 시간 감소, 읽기 처리량 확장
발표 도입 (5분)
왜 복제가 필요한가?
데이터를 단일 서버에만 저장하면 세 가지 근본적 한계에 부딪힙니다.
- 가용성(Availability): 서버 한 대가 죽으면 서비스 전체가 중단됩니다.
- 지연 시간(Latency): 서울에서 미국 서버까지 왕복 150ms — 사용자 체감으로는 답답합니다.
- 읽기 처리량(Read Throughput): 트래픽이 폭증하면 단일 서버의 CPU/IO가 병목이 됩니다.
복제(Replication) 는 동일한 데이터의 복사본을 네트워크로 연결된 여러 머신에 유지하여 이 세 가지 문제를 동시에 해결하는 기법입니다.
┌──────────┐
쓰기 ──────▶ │ 리더(L) │
└────┬─────┘
│ 복제 스트림
┌─────────┼─────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│팔로워 1 │ │팔로워 2 │ │팔로워 3 │ ◀── 읽기 분산
└─────────┘ └─────────┘ └─────────┘
복제의 세 가지 아키텍처
| 아키텍처 | 쓰기 노드 | 대표 시스템 | 핵심 트레이드오프 |
|---|---|---|---|
| 단일 리더 |
1개 | MySQL, PostgreSQL, MongoDB | 단순하지만 쓰기 확장 불가 |
| 다중 리더 |
N개 (보통 DC당 1개) | Aurora Multi-Writer, CouchDB | 쓰기 확장 가능하지만 충돌 해소 필요 |
| 리더 없음 |
모든 노드 | Cassandra, Riak, DynamoDB | 고가용성이지만 일관성 보장 복잡 |
발표 전체를 관통하는 핵심 메시지: 복제에서 "은탄환"은 없습니다. 모든 선택은 일관성(Consistency) vs 가용성(Availability) vs 지연 시간(Latency) 사이의 트레이드오프입니다.
상세 내용
테마 1: 단일 리더 복제 (25분)
1-1. 리더와 팔로워
단일 리더 복제(Single-Leader Replication) 는 가장 일반적인 복제 방식입니다. 핵심 원리는 단순합니다:
클라이언트 ──▶ 리더 ──▶ 복제 로그 ──▶ 팔로워들
↓
동일한 순서로 적용
역할 분담:
- 리더(Leader): 모든 쓰기 요청을 받아 처리. 마스터(Master), 프라이머리(Primary)라고도 불림
- 팔로워(Follower): 리더의 변경 사항을 복제하여 적용. 읽기 전용 복제본(Read Replica), 슬레이브(Slave), 세컨더리(Secondary)라고도 불림
장점
- 쓰기 충돌이 발생하지 않음 (모든 쓰기가 단일 노드에서 순서화)
- 구현이 상대적으로 단순
- 대부분의 워크로드에 적합
단점:
- 리더가 병목 (쓰기 확장이 어려움)
- 리더 장애 시 failover 필요
1-2. 동기식 대 비동기식 복제
복제에서 가장 먼저 결정해야 하는 것은 "쓰기 완료를 팔로워 확인까지 기다릴 것인가?"입니다.
[동기 복제]
클라이언트 ──▶ 리더 ──▶ 팔로워 확인 대기 ──▶ 클라이언트에 "성공" 응답
장점: 팔로워가 항상 최신 데이터 보유
단점: 팔로워 1대라도 응답 못하면 전체 쓰기 중단
[비동기 복제]
클라이언트 ──▶ 리더 ──▶ 클라이언트에 즉시 "성공" 응답
└──▶ 팔로워에 나중에 전파 (백그라운드)
장점: 쓰기 지연 최소화, 가용성 높음
단점: 팔로워가 뒤처질 수 있음 (복제 지연)
반동기(Semi-Synchronous) 복제 — Facebook의 선택:
- 팔로워 중 1대만 동기적으로 확인, 나머지는 비동기
- 동기 팔로워가 죽으면 다른 팔로워를 동기 팔로워로 승격
- 최소 2개 노드에 데이터가 있음을 보장하면서 성능도 확보
- 참고: Yoshinori Matsunobu, "Semi-Synchronous Replication at Facebook," 2014
실무 포인트: 대부분의 프로덕션 시스템(MySQL, PostgreSQL 등)은 비동기 복제가 기본값입니다. 그런데 비동기 복제를 선택하는 순간, 복제 지연(Replication Lag)이 생김
1-3. 새로운 팔로워 설정
운영 중인 시스템에 새로운 팔로워를 추가할 때, 서비스를 중단하지 않고 어떻게 할 수 있을까요?
일반적인 절차:
1. 리더의 데이터베이스 스냅샷을 특정 시점에 생성
└── 가능하면 백업 기능 활용 (잠금 없이)
2. 스냅샷을 새 팔로워 노드에 복사
3. 팔로워가 스냅샷을 로드한 후, 스냅샷 이후의 변경 사항을 리더에게 요청
└── 스냅샷은 리더의 복제 로그에서 정확한 위치와 연결되어 있어야 함
└── PostgreSQL: LSN (Log Sequence Number)
└── MySQL: binlog coordinates
4. 팔로워가 밀린 로그를 모두 따라잡으면 정상 동작
└── "caught up" 상태가 됨
PostgreSQL 예시:
-- 스냅샷 위치 확인
SELECT pg_current_wal_lsn();
-- 결과: 0/16B3748
-- 새 팔로워는 이 LSN 이후의 WAL부터 요청
1-4. 노드 중단 처리
노드 장애는 크게 두 가지로 나뉩니다: 팔로워 장애와 리더 장애.
팔로워 장애: Catch-up Recovery
팔로워 장애 발생
↓
복구 후 로컬 로그에서 마지막 처리한 트랜잭션 확인
↓
리더에게 해당 시점 이후의 변경 사항 요청
↓
밀린 로그 모두 적용 → 정상 동작
- 팔로워는 자신이 마지막으로 처리한 트랜잭션을 로컬에 기록
- 복구 후 이 시점부터 리더의 로그를 따라잡으면 됨
리더 장애: Failover
리더가 죽었을 때 팔로워를 새 리더로 승격하는 과정입니다.
1. 리더 장애 감지
- 타임아웃 기반: N초간 하트비트 없으면 장애로 판단
- 문제: 너무 짧으면 불필요한 failover, 너무 길면 복구 지연
2. 새 리더 선출
- 가장 최신 데이터를 가진 팔로워 선택 (이상적)
- 합의 알고리즘(Raft, Paxos)으로 선출
3. 시스템 재구성
- 클라이언트의 쓰기를 새 리더로 리다이렉트
- 이전 리더가 복구되면 팔로워로 강등
스플릿 브레인(Split Brain) — 가장 위험한 장애 시나리오:
네트워크 파티션 발생:
┌──────────────────┐ ┌──────────────────┐
│ 이전 리더 (살아있음)│ ✗ │ 새 리더 (승격됨) │
│ "나도 리더다!" │ │ "나도 리더다!" │
│ 쓰기A 수신 중 │ │ 쓰기B 수신 중 │
└──────────────────┘ └──────────────────┘
↓
두 리더에 서로 다른 데이터!
네트워크 복구 후 어떻게 합치나?
결과: 두 리더에 서로 다른 쓰기가 발생 → 데이터 불일치 → 복구가 매우 어려움
GitHub 2012년 사고:
- MySQL 리더 장애 → 자동 failover로 팔로워 승격
- 이전 리더가 복구되었지만, 새 리더와 데이터가 불일치
- 결과: 일부 데이터가 유실되고, 수동 복구에 오랜 시간 소요
펜싱(Fencing) 메커니즘:
방법 1: STONITH (Shoot The Other Node In The Head)
새 리더 선출 → 이전 리더에 전원 차단 명령 (IPMI/iLO)
→ 물리적으로 확실히 중단시킴
- 가장 확실하지만 하드웨어 의존적
- 클라우드 환경에서는 인스턴스 강제 종료로 대체
방법 2: 펜싱 토큰(Fencing Token)
리더 선출 시 단조 증가하는 토큰 발급:
이전 리더: token = 33
새 리더: token = 34
스토리지는 token 34 이후부터 token 33의 쓰기를 거부
→ 이전 리더가 좀비 상태로 쓰기해도 무시됨
방법 3: 리스(Lease) 기반
리더가 일정 시간(예: 10초) 동안만 유효한 리더십 임대(lease) 획득
→ 갱신하지 않으면 자동 만료
→ 만료 후 다른 노드가 새 리더 임대 획득
1-5. 복제 로그 구현
리더가 팔로워에게 "무엇을 복제할 것인가"를 전달하는 방식에는 세 가지가 있습니다.
방식 1: 구문 기반(Statement-Based) 복제
리더 → 팔로워: "INSERT INTO users (name) VALUES ('Kim')"
- 리더가 실행한 SQL 문 자체를 팔로워에 전송
- 문제점:
NOW(),RAND()→ 리더와 팔로워에서 다른 결과- AUTO_INCREMENT → 실행 순서에 따라 다른 값
- 부수 효과가 있는 트리거, 함수 → 비결정적 결과
- MySQL 5.1 이전의 기본 방식이었으나, 현재는 거의 사용하지 않음
방식 2: WAL(Write-Ahead Log) 기반 복제
리더 → 팔로워: "페이지 42, 오프셋 128에 바이트 0x4B696D 기록"
- 스토리지 엔진의 물리적 변경(디스크 블록 단위)을 그대로 전송
- PostgreSQL, Oracle이 이 방식 사용
- 장점: 완벽하게 정확한 복제
- 단점: 스토리지 엔진의 내부 포맷에 종속 → 버전이 다른 리더-팔로워 간 복제 불가 → 무중단 업그레이드가 어려움
방식 3: 논리적 로우 기반(Row-Based / Logical) 복제
리더 → 팔로워: "users 테이블, id=42, name='Kim' → name='Park' 변경"
- 변경된 행의 논리적 내용을 전송
- MySQL의 binlog (row format), PostgreSQL의 logical decoding
- 장점:
- 스토리지 엔진 독립 → 버전 간 호환성 좋음
- 외부 시스템(데이터 웨어하우스, 검색 엔진)으로 변경 데이터 캡처(CDC) 가능
- 단점: 대규모 변경 시 로그 크기가 큼
테마 1 토론
"Failover를 자동화해야 하는가, 수동으로 해야 하는가?"
토론 유도 질문:
- 자동 failover의 위험성은 무엇인가? (스플릿 브레인, 잘못된 판단)
- 수동 failover의 비용은 무엇인가? (장애 시간 증가, 24/7 운영 인력)
- 어떤 상황에서 자동/수동을 선택해야 하는가?
테마 1 참고자료 상세 해설
Lindsay et al., "Notes on Distributed Databases" (IBM Research, 1979)
IBM 연구소에서 나온 분산 데이터베이스의 기초 이론 문서
- 1979년에 작성되었지만 분산 DB의 근본 문제를 정의한 선구적 연구
- 다루는 주제: 데이터 분산, 복제, 분산 트랜잭션, 장애 복구
- 복제 시 발생하는 일관성 vs 가용성 트레이드오프를 최초로 체계적으로 정리
- "분산 시스템의 어려움은 네트워크가 아니라 부분 장애(partial failure)"라는 통찰
Oracle Active Data Guard White Paper (2013)
Oracle의 물리적 대기 서버(Standby) 복제 기술 문서
- Active Data Guard: 팔로워(Standby)에서도 읽기 쿼리를 처리 가능 → 읽기 부하 분산
- WAL(Redo Log) 기반 물리적 복제: 블록 단위로 정확하게 복제
- 실시간 적용(Real-Time Apply): 리더에서 Redo Log가 생성되는 즉시 팔로워에 적용
- 자동 장애 복구(Data Guard Broker): 장애 감지 → 자동 Failover → 이전 리더 복구 시 팔로워로 재합류
Kafka Intra-Cluster Replication (ApacheCon, 2013)
Apache Kafka의 브로커 간 복제 메커니즘 발표:
- Kafka는 로그 기반 메시지 시스템 → 복제도 로그 기반으로 자연스럽게 구현
- ISR(In-Sync Replicas): 리더와 동기화가 된 팔로워 목록을 유지
- 뒤처진 팔로워는 ISR에서 제거 → 따라잡으면 다시 추가
acks=all로 설정하면 ISR 내 모든 복제본에 기록 완료 후 응답 → 데이터 유실 방지
- 리더 선출: ISR 중에서만 새 리더를 선출 → 데이터가 있는 노드만 리더가 될 수 있음
unclean.leader.election.enable=true이면 ISR 외 노드도 리더 가능 → 데이터 유실 위험 vs 가용성 트레이드오프
Yoshinori Matsunobu, "Semi-Synchronous Replication at Facebook" (2014)
Facebook의 MySQL 인프라 엔지니어가 반동기 복제 운영 경험을 공유한 발표:
- Facebook은 수천 대의 MySQL 서버를 운영하며, 비동기 복제의 데이터 유실 위험을 해결해야 했음
- 반동기 복제(Semi-Synchronous): 리더가 쓰기를 커밋하기 전에 최소 1대의 팔로워 확인을 대기
- 모든 팔로워를 기다리지 않으므로 동기 복제보다 빠름
- 최소 2곳에 데이터가 있으므로 비동기보다 안전
- 문제: 반동기 팔로워가 느려지면? → 전체 쓰기 지연 증가
- 해결: 타임아웃 기반 전환 — 일정 시간 내 팔로워 응답이 없으면 비동기 모드로 자동 전환
Chain Replication (van Renesse & Schneider, OSDI 2004)
전통적 리더-팔로워와 다른 체인 복제 아키텍처를 제안한 논문:
- 노드들을 일렬 체인으로 구성: Head → N1 → N2 → ... → Tail
- 쓰기: Head에서 시작하여 체인을 따라 순차 전파, Tail에 도달하면 커밋
- 읽기: 항상 Tail에서만 수행 → 강한 일관성 보장
- Microsoft Azure Storage, HDFS, Amazon EBS 등에서 변형 채택
테마 2: 복제 지연 문제 (25분)
2-1. 복제 지연 문제
비동기 복제를 선택하는 순간, 복제 지연(Replication Lag) 이라는 판도라의 상자가 열립니다.
최종적 일관성(Eventual Consistency)의 정의:
모든 쓰기가 중단되고 충분한 시간이 지나면, 모든 복제본이 결국 동일한 데이터를 가지게 됩니다.
이 정의에서 핵심 단어는 "결국(Eventually)" 입니다 — 언제인지는 보장하지 않습니다.
시간 → t0 t1 t2 t3
리더: [v2] [v2] [v2] [v2]
팔로워A: [v1] → [v2] [v2] [v2] (빠르게 따라잡음)
팔로워B: [v1] [v1] → [v1] → [v2] (느리게 따라잡음)
↑ ↑
복제 지연 이 구간에서 B를 읽으면 stale 데이터
복제 지연이 발생하는 근본 원인:
- 네트워크 지연: DC 간 물리적 거리, 네트워크 혼잡
- 팔로워 부하: 팔로워가 읽기 쿼리 처리로 바빠서 복제 스트림 적용이 느려짐
- 장애 복구: 팔로워가 재시작 후 밀린 로그를 따라잡는 동안
- 대규모 트랜잭션: 한 번에 수백만 행을 변경하는 배치 작업
Werner Vogels(Amazon CTO)는 2008년 "Eventually Consistent" 논문에서 최종적 일관성을 여러 변형으로 분류했습니다.
2-2. 자신이 쓴 내용 읽기(Read-Your-Own-Writes)
시나리오: 사용자가 프로필 사진을 변경한 직후 페이지를 새로고침하면, 아직 복제되지 않은 팔로워에서 읽어 이전 사진이 그대로 보입니다.
사용자A: "프로필 사진 변경" ──▶ 리더 (v2 저장 완료)
사용자A: "내 프로필 확인" ──▶ 팔로워B (아직 v1) ──▶ "어? 안 바뀌었네?"
(사실은 바뀐 건데)
이것은 단순한 불편이 아닙니다. 사용자는 "내 데이터가 사라졌다"고 느끼며, 이는 서비스 신뢰도에 직결됩니다.
구현 전략:
| 전략 | 구현 방법 | 적합한 상황 |
|---|---|---|
| 리더 라우팅 | 사용자가 수정한 데이터는 항상 리더에서 읽기 | 수정 빈도가 낮은 데이터 (프로필 등) |
| 타임스탬프 기반 | 클라이언트가 마지막 쓰기 시각을 기억 → 해당 시각 이후의 복제본에서만 읽기 | 범용적이지만 시계 동기화 필요 |
| 논리적 타임스탬프 | 물리 시계 대신 로그 시퀀스 번호(LSN) 활용 | 시계 스큐 문제 회피 |
크로스 디바이스 문제
- 사용자가 노트북에서 쓰고 스마트폰에서 확인하면?
- 디바이스 간 "마지막 쓰기 타임스탬프"를 공유해야 하는데, 이는 추가 인프라(세션 서버 등)를 요구합니다
2-3. 단조 읽기(Monotonic Reads)
시나리오: 사용자가 새로고침할 때마다 다른 팔로워에 라우팅되면, "있었던 댓글이 사라졌다가 다시 나타나는" 현상이 발생합니다.
첫 번째 읽기 → 팔로워A (v2: 댓글 3개 보임)
두 번째 읽기 → 팔로워B (v1: 댓글 2개만 보임) ← "시간이 역행하는 느낌"
세 번째 읽기 → 팔로워A (v2: 다시 댓글 3개 보임)
해결: 세션 고정(Session Stickiness)
- 동일 사용자는 항상 동일 복제본에서 읽도록 라우팅
- 구현 방법: 사용자 ID의 해시값으로 팔로워 결정
- 주의: 해당 팔로워가 죽으면 다른 팔로워로 전환 필요
2-4. 일관된 순서로 읽기(Consistent Prefix Reads)
시나리오: 인과성 위반 — 질문보다 답변이 먼저 보이는 현상
리더에서의 실제 순서:
t1: Mr.Poons "Mrs. Cake, 미래를 볼 수 있다면서요?" (파티션 1에 저장)
t2: Mrs.Cake "네, 아쉽게도 그래요." (파티션 2에 저장)
관찰자가 보는 순서 (파티션 2의 복제가 더 빠른 경우):
t1: Mrs.Cake "네, 아쉽게도 그래요." ← ???
t2: Mr.Poons "Mrs. Cake, 미래를 볼 수 있다면서요?"
근본 원인: 서로 다른 파티션에 기록된 데이터의 복제 속도가 다르면, 인과적 순서가 뒤집힐 수 있습니다.
해결 방향:
- 인과적으로 관련된 쓰기를 동일 파티션에 배치
- 인과 관계를 명시적으로 추적(Lamport 타임스탬프, 벡터 클럭)
- 참고: Leslie Lamport, "Time, Clocks, and the Ordering of Events" (1978) — 분산 시스템에서 인과적 순서를 정의한 기념비적 논문
2-5. 복제 지연을 위한 해결책
야구로 이해하는 일관성 모델
Douglas Terry의 "Replicated Data Consistency Explained Through Baseball" (2011) 논문에서는 야구 경기 점수판을 비유로 사용합니다.
실제 경기 상황: 방문팀 2 - 5 홈팀 (7회 끝)
각 일관성 모델에서 관찰 가능한 값:
┌────────────────────────────┬────────────────────────┐
│ 일관성 모델 │ 볼 수 있는 점수 │
├────────────────────────────┼────────────────────────┤
│ 강한 일관성(Strong) │ 2-5 (정확히 최신) │
│ 최종적 일관성(Eventual) │ 아무 과거 점수나 가능 │
│ 자신이 쓴 내용 읽기 │ 내가 마지막 본 이후 값 │
│ 단조 읽기(Monotonic) │ 이전 읽기보다 같거나 앞 │
│ 일관된 순서(Prefix) │ 일부 이닝까지의 정확한값│
└────────────────────────────┴────────────────────────┘
핵심 인사이트: 모든 상황에 강한 일관성이 필요한 것은 아닙니다. 야구 점수를 보는 팬에게는 약간의 지연이 괜찮지만, 공식 기록원에게는 강한 일관성이 필수입니다. 워크로드에 맞는 일관성 모델을 선택하는 것이 핵심입니다.
실무적 해결 방법들:
| 문제 | 해결책 | 구현 예시 |
|---|---|---|
| 자신이 쓴 내용 읽기 | 리더에서 읽기, LSN 기반 라우팅 | MySQL WAIT_FOR_EXECUTED_GTID_SET |
| 단조 읽기 | 세션 고정 | 로드밸런서의 sticky session |
| 일관된 순서 읽기 | 동일 파티션 배치, 인과 관계 추적 | Kafka의 파티션 키 |
운영 가시성: 복제 상태 모니터링
MySQL: SHOW REPLICA STATUS → Seconds_Behind_Source
PG: pg_stat_replication → replay_lag
알림 기준 예시:
- 복제 지연 > 5초: WARNING
- 복제 지연 > 30초: CRITICAL
- 복제 중단: PAGE (on-call 호출)
테마 2 토론
"성능을 위해 일관성을 어디까지 희생할 수 있는가?"
토론 유도 질문:
- SNS 타임라인에서 "좋아요" 수가 1~2초 뒤처지는 것은 괜찮은가?
- 은행 잔고 조회에서 복제 지연이 허용되는가?
- 전자상거래 재고 수량은 어떤 일관성 모델이 적절한가?
테마 2 참고자료 상세 해설
Werner Vogels, "Eventually Consistent" (ACM Queue, 2008)
Amazon CTO인 Werner Vogels가 쓴 이 글은 "최종적 일관성"이라는 용어를 업계에 대중화한 핵심 문헌입니다. 핵심 주장:
- 일관성에는 클라이언트 측(client-side)과 서버 측(server-side) 두 가지 관점이 존재
- 클라이언트 측 일관성 모델: 최종적 일관성, 단조 읽기, 세션 일관성, 자신이 쓴 내용 읽기 등으로 세분화됨
- N/W/R 값 튜닝을 통해 일관성과 가용성의 균형을 조절할 수 있음
Douglas B. Terry, "Replicated Data Consistency Explained Through Baseball" (Microsoft Research, 2011)
Microsoft Research의 Terry가 작성한 이 논문은 복잡한 일관성 모델을 야구 경기 비유로 직관적으로 설명합니다:
- 6가지 일관성 모델을 야구 점수판으로 비교
- 같은 데이터(야구 점수)라도 역할에 따라 필요한 일관성 수준이 다름
- 대부분의 애플리케이션은 강한 일관성 없이도 동작할 수 있음
#48: Peter Bailis et al., "Quantifying Eventual Consistency with PBS" (CACM, 2014)
PBS(Probabilistically Bounded Staleness)라는 개념을 제안한 논문:
- "최종적 일관성"이 구체적으로 얼마나 빨리 일관성이 달성되는가?를 정량화
- 실제 Cassandra, Riak 등의 시스템에서 측정한 결과, 대부분의 읽기는 수십 밀리초 내에 최신 값을 반환함
#54: Leslie Lamport, "Time, Clocks, and the Ordering of Events in a Distributed System" (CACM, 1978)
분산 시스템 분야에서 가장 많이 인용되는 논문 중 하나:
- "happens-before" 관계 (→): 이벤트 A가 이벤트 B 이전에 발생했다면 A → B
- 논리적 클럭(Logical Clock): 각 프로세스가 단조 증가하는 카운터를 유지
#61: Schwarz & Mattern, "Detecting Causal Relationships in Distributed Computations" (1994)
Lamport의 논리적 클럭을 확장하여 인과 관계를 완전하게 포착하는 방법을 연구:
- 벡터 클럭(Vector Clock): 각 프로세스별 카운터를 벡터로 유지 → 두 이벤트가 인과 관계인지, 동시인지 정확히 판별 가능
테마 3: 다중 리더 복제 (25분)
3-1. 다중 리더 복제
다중 리더 복제(Multi-Leader Replication) 는 여러 노드가 쓰기를 받을 수 있는 구조입니다. 단일 리더의 확장성 한계를 극복하기 위한 방법이지만, 쓰기 충돌이라는 새로운 문제가 발생합니다.
DC 서울 DC 미국
┌─────────────┐ ┌─────────────┐
│ 리더 (L1) │◀────────▶│ 리더 (L2) │
│ 팔로워 F1 │ │ 팔로워 F3 │
│ 팔로워 F2 │ │ 팔로워 F4 │
└─────────────┘ └─────────────┘
서울 사용자 → 미국 사용자 →
L1에 쓰기 (5ms) L2에 쓰기 (5ms)
↕
DC 간 비동기 복제 (150ms)
3-2. 다중 리더 복제의 사용 사례
상황 1: 다중 데이터센터 운영
- 각 DC에 리더를 두면 사용자는 가까운 DC에 쓸 수 있어 지연 시간이 크게 줄어듦
- 한 DC가 완전히 다운되어도 다른 DC에서 계속 서비스 가능
상황 2: 오프라인 작업 — 캘린더 앱
- 비행기 안에서 일정을 수정 → 오프라인 상태의 로컬 DB가 "리더" 역할
- 착륙 후 인터넷 연결 → 서버와 동기화
- 각 디바이스가 사실상 독립적인 리더 → 다중 리더 토폴로지와 동일
상황 3: 실시간 협업 편집 — Google Docs, Notion
- 여러 사용자가 동시에 같은 문서를 편집
- 각 사용자의 편집이 즉시 로컬에 반영되고, 서버를 통해 다른 사용자에게 전파
- 충돌이 빈번하게 발생할 수 있으며, 이를 자동으로 해소해야 함
CRDT 관련 메모:
- 다중 쓰기에서 쓰기 충돌을 해소하는 자료구조
- 클라이언트를 유니크 아이디로 식별 → LWW 사용
- 이벤트의 인과 순서로 벡터 시계를 사용
- YJS 라이브러리가 대표적인 구현체
3-3. 쓰기 충돌 다루기
쓰기 충돌이란?
사용자A (L1): title = "A" ──▶ L1에 커밋 ──▶ L2로 전파
사용자B (L2): title = "B" ──▶ L2에 커밋 ──▶ L1으로 전파
↓
충돌 발생! title은 "A"? "B"?
단일 리더 시스템에서는 두 번째 쓰기가 첫 번째 이후에 순서가 정해지므로 충돌이 원천적으로 불가능합니다. 그러나 다중 리더에서는 두 쓰기가 독립적으로 성공한 후에 충돌이 감지되므로, 사용자에게 에러를 반환하기엔 이미 늦었습니다.
충돌 해소 전략 비교:
전략 1: LWW (Last Write Wins) — 최종 쓰기 승리
쓰기A: title = "A" (timestamp: 100)
쓰기B: title = "B" (timestamp: 101)
→ 결과: title = "B" (더 큰 타임스탬프 승리)
→ 쓰기A는 조용히 사라짐 (데이터 유실!)
- Cassandra가 이 방식을 채택 (#53 "Why Cassandra Doesn't Need Vector Clocks")
- 장점: 구현이 극도로 단순
- 치명적 단점: 동시 쓰기 시 하나의 값이 아무런 알림 없이 유실됨
- 시계 스큐(clock skew)가 있으면 나중에 쓴 값이 먼저로 판정될 수도 있음
전략 2: 버전 벡터(Version Vector) — 인과 관계 추적
초기 상태: {A:0, B:0} value = ∅
사용자A가 쓰기: {A:1, B:0} value = "hello"
사용자B가 쓰기: {A:0, B:1} value = "world"
비교: {A:1, B:0} vs {A:0, B:1}
→ 어느 쪽도 다른 쪽을 지배하지 않음 → "동시 쓰기"로 판정
→ 충돌을 애플리케이션에 알려 병합하도록 위임
사용자A가 두 값을 병합: {A:2, B:1} value = "hello world"
→ 이제 이 값이 두 이전 값 모두를 지배함
- 핵심: 버전 벡터는 "누가 누구를 알고 있는가"를 추적
- 중요: 버전 벡터 ≠ 벡터 클럭 (#60 Carlos Baquero 참고)
전략 3: CRDT (Conflict-Free Replicated Data Types)
G-Counter (성장 전용 카운터) 예시:
노드A: {A:5, B:3} → 전체 값 = max 병합
노드B: {A:4, B:7} → 전체 값 = max 병합
병합: {A:5, B:7} → 총합 = 12
→ 충돌이 수학적으로 불가능!
- 교환법칙(commutativity)과 결합법칙(associativity)을 만족하는 데이터 구조
- 한계: 지원되는 연산이 제한적 (카운터, 집합, 레지스터 등)
- Riak이 CRDT를 실무에 적용한 대표 사례 (#40, #55)
- Kleppmann의 CRDT JSON (#32)은 JSON 문서 수준의 CRDT를 연구
전략 4: OT (Operational Transformation) — Google Docs의 선택
원본 텍스트: "ABC"
사용자A: insert('X', pos=1) → "AXBC"
사용자B: delete(pos=2) → "AC"
동시 적용 시 문제:
- A의 삽입이 B의 삭제 위치에 영향을 줌
- B의 삭제 위치를 1만큼 오른쪽으로 변환(transform)해야 함
변환 후:
- A에 B 적용: "AXBC" → delete(pos=3) → "AXC"
- B에 A 적용: "AC" → insert('X', pos=1) → "AXC"
→ 양쪽 결과 동일!
- 연산(operation)을 상대방의 동시 연산에 맞게 변환하여 병합
- #42 Sun & Ellis 원논문 / #31 Google Docs가 이 방식 채택
- 장점: 텍스트 편집처럼 위치 기반 연산에 강력
- 단점: 변환 함수 정의가 복잡, 3인 이상 동시 편집에서 정확성 보장이 어려움
3-4. 다중 리더 복제 토폴로지
[원형(Circular)] [별형(Star)] [전체연결(All-to-All)]
L1 → L2 L1 → Hub ← L3 L1 ←→ L2
↑ ↓ ↓ ↑↘ ↗↑
L4 ← L3 L2 L3 ←→ L4
| 토폴로지 | 장점 | 단점 |
|---|---|---|
| 원형/별형 | 네트워크 트래픽 적음 | 단일 장애점, 메시지 순서 문제 |
| 전체 연결 | 내결함성 높음 | 네트워크 비용 큼, 순서 역전 가능 |
실무 경고 (#28): Robert Hodges는 "Multi-Master를 반드시 배포해야 한다면, 이것부터 읽어라"에서 다중 리더의 운영 복잡성을 경고합니다. 무한 루프 버그(#43 HBase 사례), 트랜잭션 지원 한계(#36 PostgreSQL BDR) 등 실무에서 마주치는 문제가 많습니다.
AWS Aurora Multi-Writer vs 전통적 다중 리더:
| 항목 | Aurora Multi-Writer | 전통적 다중 리더 (Tungsten 등) |
|---|---|---|
| 복제 레벨 | 스토리지 레벨 (공유 스토리지) | 애플리케이션/논리적 레벨 |
| 충돌 감지 | 낙관적 충돌 감지 (커밋 시점) | 비동기 감지 (전파 시점) |
| 충돌 해소 | 첫 번째 커밋 승리, 나머지 롤백 | 애플리케이션 로직 필요 |
| 사용 조건 | 같은 행을 동시에 쓰지 않는 워크로드 | 범용 |
Aurora Multi-Writer는 "동일 행에 대한 동시 쓰기가 드문 경우"에 최적화되어 있습니다.
테마 3 토론
"LWW 방식에서 발생하는 데이터 유실을 비즈니스적으로 어떻게 정당화할 것인가?"
토론 유도 질문:
- 쇼핑카트에서 LWW를 쓰면 어떤 일이 발생하는가? (Amazon Dynamo 논문의 실제 사례)
- CRDT로 해결할 수 있는 비즈니스 도메인은 무엇인가?
- 여러분의 서비스에서 다중 리더가 필요한 상황이 있는가?
테마 3 참고자료 상세 해설
다중 마스터 복제 실무
#26: Tungsten Replicator (GitHub)
MySQL 환경에서 다중 마스터 복제를 구현하는 오픈소스 도구:
- MySQL의 기본 복제 기능을 넘어 이기종 DB 간 복제(MySQL → PostgreSQL 등)도 지원
- 충돌 해소를 자동으로 해주지 않음 → 애플리케이션에서 직접 충돌 해소 로직을 구현해야 함
#27: BDR 0.10.0 Documentation (PostgreSQL)
PostgreSQL을 위한 양방향 복제(Bi-Directional Replication) 확장:
- 모든 노드가 읽기/쓰기 가능 → 다중 마스터 토폴로지
- 충돌 감지 및 해소: last-update-wins가 기본이며, 커스텀 충돌 해소 핸들러를 작성할 수 있음
#28: Robert Hodges, "If You Must Deploy Multi-Master Replication, Read This First" (2012)
Tungsten Replicator의 개발자인 Robert Hodges가 쓴 실무 경고문:
- 다중 마스터 복제는 "해결책"이 아니라 "새로운 문제의 시작"
- 자주 발생하는 실무 문제들:
- AUTO_INCREMENT 충돌: 두 마스터가 같은 ID를 생성
- DDL(스키마 변경) 전파: ALTER TABLE이 비동기로 전파되면 스키마 불일치 발생
- 결론: "정말 필요한 경우가 아니면 단일 마스터를 쓰라"
#43: Lars Hofhansl, "HBASE-7709: Infinite Loop in Master/Master Replication" (2013)
HBase에서 발견된 다중 마스터 복제의 무한 루프 버그:
- Master A → Master B로 복제, Master B → Master A로 다시 복제 → 동일 변경이 무한히 순환
충돌 해소 알고리즘
#31: John Day-Richter, "What's Different About the New Google Docs" (2010)
Google Docs가 OT 기반 실시간 협업 편집을 어떻게 구현했는지 설명하는 공식 블로그:
- 서버가 중앙 변환점 역할
- 클라이언트 측에서도 서버 응답을 받기 전까지 로컬 예측 적용(optimistic UI)
#32: Martin Kleppmann & Beresford, "A Conflict-Free Replicated JSON Datatype" (arXiv, 2016)
DDIA 저자인 Kleppmann의 연구로, JSON 문서 전체에 대한 CRDT를 설계한 논문:
- 중첩된 맵(map)과 리스트(list)를 포함하는 JSON 구조 전체를 CRDT로 처리
- 이후 Automerge 라이브러리로 오픈소스 구현됨
#38: Marc Shapiro et al., "A Comprehensive Study of Convergent and Commutative Replicated Data Types" (INRIA, 2011)
CRDT의 바이블이라 불리는 종합 연구 논문:
- CRDT를 CvRDT(상태 기반)와 CmRDT(연산 기반) 두 가지로 분류
- 구체적 CRDT 타입 카탈로그: G-Counter, PN-Counter, G-Set, 2P-Set, OR-Set, LWW-Register, MV-Register, RGA(리스트) 등
#42: Sun & Ellis, "Operational Transformation in Real-Time Group Editors" (CSCW, 1998)
OT(Operational Transformation) 알고리즘의 원논문:
- 핵심 속성:
- TP1(Transformation Property 1): O1; T(O2, O1) = O2; T(O1, O2)
- TP2: 3개 이상 동시 연산에도 수렴 보장
버전 벡터 관련
#53: Jonathan Ellis, "Why Cassandra Doesn't Need Vector Clocks" (DataStax, 2013)
Cassandra 프로젝트 리더가 LWW(Last Write Wins)를 선택한 실용적 이유를 설명한 글:
- "대부분의 애플리케이션에서 LWW가 충분히 좋고, 데이터 유실 위험보다 구현 단순성이 더 가치 있다"
- cell 단위(컬럼 단위) LWW → 행 전체가 아닌 각 컬럼별로 최신 값을 선택
#56: Parker et al., "Detection of Mutual Inconsistency in Distributed Systems" (IEEE, 1983)
버전 벡터(Version Vector)의 원논문:
- 각 복제본이
[n1, n2, ..., nk]형태의 벡터를 유지
#60: Carlos Baquero, "Version Vectors Are Not Vector Clocks" (2011)
자주 혼동되는 버전 벡터와 벡터 클럭의 차이를 명확히 정리한 글:
- 벡터 클럭(Vector Clock): 이벤트(프로세스의 각 동작)에 부여
- 버전 벡터(Version Vector): 데이터 객체의 버전에 부여
테마 4: 리더 없는 복제 (25분)
4-1. 리더 없는 복제
Amazon의 Dynamo 논문(2007, #37)에서 대중화된 아키텍처로, 어떤 노드든 쓰기를 직접 받을 수 있습니다.
클라이언트
╱ │ ╲
쓰기 쓰기 쓰기
╱ │ ╲
┌─────┐ ┌─────┐ ┌─────┐
│ N1 │ │ N2 │ │ N3 │ n=3
│ v2 │ │ v2 │ │(장애)│ w=2 → 2개 성공이면 쓰기 OK
└─────┘ └─────┘ └─────┘
읽기 읽기 읽기
╱ │ ╲
┌─────┐ ┌─────┐ ┌─────┐
│ N1 │ │ N2 │ │ N3 │ r=2 → 2개 읽어서 최신 값 선택
│ v2 │ │ v2 │ │ v1 │ (N3 복구 후에도 아직 v1)
└─────┘ └─────┘ └─────┘
→ v2를 2개 확인 → 최신 값 v2 반환
핵심 차이점: 리더가 없으므로 장애 복구(failover)가 필요 없습니다. 노드가 죽었다 살아나면 그냥 다시 참여하면 됩니다.
정족수(Quorum) 공식: w + r > n
수학적 직관:
- n개의 노드 중 w개에 쓰기 성공
- n개의 노드 중 r개에서 읽기
- w + r > n이면, 쓰기 셋과 읽기 셋이 반드시 1개 이상 겹침
- 겹치는 노드에 최신 값이 있으므로 → 최신 값 획득 보장
n=3 일 때:
노드: [N1] [N2] [N3]
w=2 쓰기: [✓] [✓] [ ] ← 2개에 기록
r=2 읽기: [ ] [✓] [✓] ← 2개에서 읽기
↑
겹치는 노드! (N2에 최신 값)
주요 설정과 그 특성:
| 설정 | w + r | 내결함성 | 특징 |
|---|---|---|---|
| n=3, w=2, r=2 | 4 > 3 ✓ | 1대 장애 허용 | 가장 일반적인 균형 설정 |
| n=5, w=3, r=3 | 6 > 5 ✓ | 2대 장애 허용 | 높은 가용성 요구 시 |
| n=3, w=3, r=1 | 4 > 3 ✓ | 쓰기 시 0대 장애 허용 | 읽기 최적화 (1대만 읽으면 됨) |
| n=3, w=1, r=3 | 4 > 3 ✓ | 읽기 시 0대 장애 허용 | 쓰기 최적화 (1대만 쓰면 됨) |
| n=3, w=1, r=1 | 2 < 3 ✗ | 높은 가용성 | 최신성 보장 안됨! |
4-2. 노드가 다운됐을 때 데이터베이스에 쓰기
읽기 복구(Read Repair):
클라이언트가 r=2로 읽기:
N1 → v2 (최신)
N3 → v1 (오래됨)
클라이언트: "N3이 뒤처져 있네" → N3에 v2 기록 (배경에서)
- 읽기 요청이 올 때마다 자동으로 복구
- 장점: 즉시 복구, 추가 프로세스 불필요
- 단점: 자주 읽히는 데이터만 복구됨 → 거의 안 읽히는 데이터는 방치
안티 엔트로피(Anti-Entropy):
백그라운드 프로세스가 주기적으로:
N1의 데이터 해시 vs N2의 데이터 해시 vs N3의 데이터 해시
→ 불일치 발견 → 최신 값으로 동기화
- 머클 트리(Merkle Tree)를 사용해 효율적으로 불일치 탐지
- 장점: 모든 데이터를 커버
- 단점: 동기화까지 지연 있음, CPU/네트워크 부하
4-3. 정족수 일관성의 한계
정족수 공식을 만족하더라도 다음 상황에서 stale 데이터를 읽을 수 있습니다:
Case 1: 동시 쓰기
- 두 클라이언트가 동시에 같은 키를 쓰면, 각 노드에 서로 다른 값이 기록될 수 있음
- w + r > n을 만족해도 "어느 값이 최신인가?"를 판단할 수 없음
Case 2: 부분적 쓰기 실패
- w개 미만의 노드에만 기록되어 쓰기가 "실패"로 보고됨
- 그러나 이미 기록된 노드에서 값이 남아 있어, 읽기 시 이 값이 반환될 수 있음
- 롤백이 되지 않으므로 "실패한 쓰기의 유령"이 돌아다님
Case 3: 복구 시점 문제
- 새 값을 가진 노드가 장애 → 복구 시 예전 값으로 복원될 수 있음
4-4. 느슨한 정족수와 암시된 핸드오프
느슨한 정족수(Sloppy Quorum):
정상 상황: 쓰기 → N1, N2, N3 중 w=2에 기록
N2, N3 장애 발생 시 (느슨한 정족수):
쓰기 → N1, N4(임시 대리), N5(임시 대리) ← w=2 충족!
읽기 → N1, N3(복구됨) ← r=2 충족!
↑
N4에 쓴 값을 N3은 모름 → stale 데이터!
- 느슨한 정족수는 가용성을 높이지만 일관성은 보장하지 않음
힌트된 핸드오프(Hinted Handoff, #49):
임시 대리 노드가 원래 노드 복구 시 데이터를 전달하는 메커니즘:
- 장애 노드 대신 다른 노드가 "힌트"(대리 기록)를 저장
- 장애 노드가 복구되면 힌트된 데이터를 전달하여 동기화
4-5. 동시 쓰기 감지
두 이벤트 A, B의 관계는 세 가지 중 하나입니다:
1. A → B (A가 B 이전에 발생)
A의 결과를 B가 알고 있음 → B가 A를 덮어씀
2. B → A (B가 A 이전에 발생)
B의 결과를 A가 알고 있음 → A가 B를 덮어씀
3. A ∥ B (동시 발생 = concurrent)
서로의 존재를 모름 → 충돌 해소 필요
구체적 알고리즘 — 서버 측 버전 번호:
1. 서버가 각 키에 버전 번호를 유지
2. 클라이언트가 읽을 때 버전 번호 포함하여 반환
3. 클라이언트가 쓸 때 이전 읽기의 버전 번호를 같이 보냄
4. 서버는 해당 버전 이하의 값을 덮어쓰고,
동시 쓰기(더 높은 버전이 없는 값)는 "형제(sibling)"로 유지
5. 클라이언트가 다음에 읽을 때 모든 형제를 받아서 병합
테마 4 토론
"왜 모든 데이터베이스가 리더 없는 복제 방식을 선택하지 않는가?"
토론 유도 질문:
- 리더 없는 복제에서 트랜잭션(ACID)을 지원하기 어려운 이유는?
- w=1, r=1 설정의 유혹 — 성능은 좋지만 무엇을 잃는가?
- Cassandra가 LWW를 선택한 실용적 이유는 무엇인가?
테마 4 참고자료 상세 해설
#37: DeCandia et al., "Dynamo: Amazon's Highly Available Key-Value Store" (SOSP, 2007)
리더 없는 복제의 바이블이자, 이 테마 전체의 기반이 되는 논문.
Amazon이 내부 쇼핑카트 등 핵심 서비스를 위해 만든 Dynamo 시스템의 설계:
- 설계 철학: "항상 쓰기 가능(always writable)" — 가용성을 일관성보다 우선
- 핵심 기술들의 조합:
- 일관성 해싱(Consistent Hashing): 노드 추가/제거 시 데이터 이동 최소화
- 정족수(Quorum): w + r > n으로 읽기 시 최신 값 획득 확률 향상
- 벡터 클럭: 동시 쓰기 감지
- 힌트된 핸드오프(Hinted Handoff): 장애 노드 대신 임시 노드가 쓰기를 받고, 복구 후 전달
- 머클 트리(Merkle Tree): 안티 엔트로피 과정에서 효율적 불일치 탐지
- 가십 프로토콜(Gossip Protocol): 멤버십/장애 감지를 분산적으로 수행
- 쇼핑카트 충돌 해소 사례: 두 카트 버전이 동시에 존재하면 "합집합"으로 병합
#44: David K. Gifford, "Weighted Voting for Replicated Data" (SOSP, 1979)
정족수(Quorum) 개념의 원논문:
- 복제된 데이터에 대한 읽기/쓰기 "투표" 시스템을 최초로 제안
- 각 복제본에 가중치(weight)를 부여할 수 있음
- 1979년 논문이지만, 40년이 넘은 지금도 모든 정족수 기반 시스템의 이론적 토대
#45: Heidi Howard et al., "Flexible Paxos: Quorum Intersection Revisited" (arXiv, 2016)
정족수 교차 요건을 완화할 수 있음을 보인 논문:
- Phase 1(리더 선출) 정족수와 Phase 2(값 결정) 정족수의 합만 n을 초과하면 됨
#49: Jonathan Ellis, "Modern Hinted Handoff" (DataStax, 2012)
Cassandra의 힌트된 핸드오프(Hinted Handoff) 구현을 설명한 글:
- 힌트 저장소의 크기 제한 (디스크 공간)
- 힌트 전달 시 스로틀링 (네트워크 부하 방지)
- 힌트 만료 정책 (너무 오래된 힌트는 안티 엔트로피로 대체)
#51: Apache Cassandra Documentation
Cassandra의 공식 문서로, 정족수 설정의 실무 가이드:
- 일관성 수준(Consistency Level): ONE, QUORUM, ALL, LOCAL_QUORUM, EACH_QUORUM 등
LOCAL_QUORUM: 로컬 DC 내에서만 정족수 충족 → 다중 DC에서 지연 감소
#55: Joel Jacobson, "Riak 2.0: Data Types" (2014)
Riak 2.0에서 CRDT 기반 데이터 타입이 어떻게 사용되는지 소개:
- 지원 타입: 카운터(Counter), 집합(Set), 맵(Map), 레지스터(Register), 플래그(Flag)
- 맵(Map) 타입은 중첩 가능 → 복잡한 데이터 구조를 CRDT로 표현
정리: 복제 전략 선택 가이드 (10분)
의사결정 트리
Q1: 쓰기가 한 곳에서만 발생하면 충분한가?
├── Yes → 단일 리더 복제
│ (MySQL, PostgreSQL, MongoDB 기본)
│ ✓ 가장 단순, 대부분의 워크로드에 적합
│
└── No → Q2: 모든 노드가 대등해야 하는가?
├── No → 다중 리더 복제
│ (Aurora Multi-Writer, CouchDB)
│ ⚠ 충돌 해소 전략 필수
│
└── Yes → 리더 없는 복제
(Cassandra, Riak, DynamoDB)
⚠ 정족수 설계 + 동시 쓰기 처리 필수
복제 모델별 비교 요약
| 특성 | 단일 리더 | 다중 리더 | 리더 없음 |
|---|---|---|---|
| 쓰기 충돌 | 없음 | 있음 (해소 필요) | 있음 (해소 필요) |
| 쓰기 가용성 | 리더 장애 시 중단 | DC 장애에도 계속 | 노드 장애에도 계속 |
| 읽기 확장 | 팔로워 추가 | 팔로워 추가 | 노드 추가 |
| 쓰기 확장 | 불가 (리더 1대) | 제한적 가능 | 가능 |
| 일관성 | 가장 강함 | 약함 (비동기 DC간) | 설정에 따라 다름 |
| 구현 복잡도 | 낮음 | 높음 | 중간 |
| 대표 사용처 | OLTP 범용 | 다중 DC, 오프라인 앱 | 고가용성 KV 스토어 |
발표 핵심 정리 — 세 가지 기억할 것
- 복제는 트레이드오프의 연속이다. 일관성, 가용성, 지연 시간 중 모든 것을 동시에 만족시킬 수 없습니다.
- 비동기 복제는 기본값이다. 대부분의 시스템이 비동기를 선택하며, 그로 인한 복제 지연 문제를 애플리케이션 레벨에서 대응해야 합니다.
- 충돌 해소는 비즈니스 결정이다. LWW의 데이터 유실을 허용할지, CRDT/버전 벡터의 복잡성을 감수할지는 기술이 아닌 비즈니스 요구사항에 의해 결정됩니다.
참고 문헌
- Lindsay et al., "Notes on Distributed Databases," IBM Research, 1979
- Oracle Active Data Guard White Paper, 2013
- Kafka Intra-Cluster Replication, ApacheCon 2013
- Yoshinori Matsunobu, "Semi-Synchronous Replication at Facebook," 2014
- Chain Replication (van Renesse & Schneider), OSDI 2004
- Werner Vogels, "Eventually Consistent," ACM Queue, 2008
- Douglas B. Terry, "Replicated Data Consistency Explained Through Baseball," 2011
테마별 참고자료 매핑
테마 1: 단일 리더 복제 (25분)
리더-팔로워 구조의 기본 원리, 동기/비동기 복제, 새로운 팔로워 설정, 노드 중단 처리, 복제 로그 구현을 다룹니다.
관련 참고자료
| # | 참고자료 | 핵심 키워드 |
|---|---|---|
| - | Lindsay et al., "Notes on Distributed Databases" (1979) | 분산 DB 기초 |
| - | Oracle Active Data Guard White Paper (2013) | Oracle 복제 |
| - | Kafka Intra-Cluster Replication (ApacheCon 2013) | Kafka 복제 로그 |
| - | Yoshinori Matsunobu, "Semi-Synchronous Replication at Facebook" (2014) | Facebook 반동기 복제 |
| - | Chain Replication (van Renesse & Schneider, OSDI 2004) | 체인 복제 |
| 29 | CouchDB: The Definitive Guide | CouchDB 복제 구현 |
| 35 | John Daily, "Clocks Are Bad, or, Welcome to Distributed Systems" | 분산 시스템 시계 문제 |
테마 2: 복제 지연 문제 (25분)
비동기 복제에서 발생하는 복제 지연(Replication Lag) 문제를 사용자 경험 측면에서 심도 있게 다룹니다.
관련 참고자료
| # | 참고자료 | 핵심 키워드 |
|---|---|---|
| - | Werner Vogels, "Eventually Consistent" (2008) | 최종적 일관성 정의 |
| - | Douglas B. Terry, "Replicated Data Consistency Explained Through Baseball" (2011) | 일관성 모델 비유 설명 |
| 48 | Peter Bailis et al., "Quantifying Eventual Consistency with PBS" | 일관성 정량화 |
| 54 | Leslie Lamport, "Time, Clocks, and the Ordering of Events" (1978) | 인과성 순서의 성경 |
| 61 | Schwarz & Mattern, "Detecting Causal Relationships in Distributed Computations" | 인과 관계 탐지 |
테마 3: 다중 리더 복제 (25분)
AWS Aurora Multi-Writer를 포함하여, 여러 곳에서 쓰기가 발생할 때의 복잡성을 다룹니다.
관련 참고자료
다중 마스터 복제
| # | 참고자료 | 핵심 키워드 |
|---|---|---|
| 26 | Tungsten Replicator | MySQL 다중 마스터 복제 도구 |
| 27 | BDR 0.10.0 Documentation (PostgreSQL) | 양방향 복제 |
| 28 | Robert Hodges, "If You Must Deploy Multi-Master Replication, Read This First" | 다중 마스터 실무 경고 |
| 34 | Robert Hodges, "State of the Art for MySQL Multi-Master" | MySQL 다중 마스터 현황 |
| 36 | Riley Berton, "Is BDR in Postgres Transactional?" | BDR 트랜잭션 한계 |
| 43 | Lars Hofhansl, "HBASE-7709: Infinite Loop in Master/Master Replication" | 다중 마스터 무한루프 버그 |
충돌 해소 알고리즘
| # | 참고자료 | 핵심 키워드 |
|---|---|---|
| 30 | AppJet/Etherpad, "EasySync Technical Manual" | 협업 편집 동기화 |
| 31 | John Day-Richter, "What's Different About the New Google Docs" | Google Docs OT |
| 32 | Martin Kleppmann, "A Conflict-Free Replicated JSON Datatype" | CRDT JSON |
| 33 | Frazer Clement, "Eventual Consistency – Detecting Conflicts" | 충돌 감지 |
| 38 | Marc Shapiro et al., "Convergent and Commutative Replicated Data Types" | CRDT 종합 연구 |
| 39 | Sam Elliott, "CRDTs: An UPDATE" | CRDT 실무 |
| 40 | Russell Brown, "A Bluffers Guide to CRDTs in Riak" | Riak CRDT |
| 42 | Sun & Ellis, "Operational Transformation in Real-Time Group Editors" | OT 알고리즘 원논문 |
버전 벡터
| # | 참고자료 | 핵심 키워드 |
|---|---|---|
| 53 | Jonathan Ellis, "Why Cassandra Doesn't Need Vector Clocks" | Cassandra LWW 선택 이유 |
| 56 | Parker et al., "Detection of Mutual Inconsistency" | 버전 벡터 원논문 |
| 57 | Nuno Preguiça et al., "Dotted Version Vectors" | 점 버전 벡터 |
| 58 | Sean Cribbs, "A Brief History of Time in Riak" | Riak 시간 관리 |
| 59 | Russell Brown, "Vector Clocks Revisited Part 2" | 버전 벡터 실무 |
| 60 | Carlos Baquero, "Version Vectors Are Not Vector Clocks" | 버전벡터 ≠ 벡터클럭 |
테마 4: 리더 없는 복제 (25분)
아마존 다이나모(Dynamo) 스타일의 시스템이 리더 없이도 어떻게 가용성을 극대화하는지 다룹니다.
관련 참고자료
| # | 참고자료 | 핵심 키워드 |
|---|---|---|
| 37 | DeCandia et al., "Dynamo: Amazon's Highly Available Key-Value Store" | Dynamo 원논문 (필독) |
| 44 | David K. Gifford, "Weighted Voting for Replicated Data" (1979) | 정족수 원논문 |
| 45 | Heidi Howard et al., "Flexible Paxos: Quorum Intersection Revisited" | 유연한 정족수 |
| 46 | Joseph Blomstedt, "Absolute Consistency" | Riak 일관성 논의 |
| 47 | Joseph Blomstedt, "Bringing Consistency to Riak" | Riak 일관성 구현 |
| 49 | Jonathan Ellis, "Modern Hinted Handoff" | 힌트된 핸드오프 |
| 50 | Project Voldemort Wiki | Voldemort 구현 |
| 51 | Apache Cassandra Documentation | Cassandra 정족수 |
| 52 | Riak Enterprise: Multi-Datacenter Replication | Riak 다중 DC |
| 55 | Joel Jacobson, "Riak 2.0: Data Types" | Riak 데이터 타입 |
발표 준비용 필독 Top 10
- #37 Dynamo 논문 - 리더 없는 복제의 바이블
- #54 Lamport 시간/순서 논문 - 인과성의 기초
- #38 CRDT 종합 연구 - 충돌 해소 이론
- #44 Gifford 정족수 논문 - w+r>n 원리
- #28 Multi-Master 실무 경고 - 토론 소스
- #32 Kleppmann CRDT JSON - 최신 연구
- #57 Dotted Version Vectors - 버전 벡터 심화
- Facebook Semi-Sync 복제 - 실무 사례
- #49 Modern Hinted Handoff - 장애 복구
- #42 OT 알고리즘 - 협업 편집 원리
발표 시간 배분 가이드
| 순서 | 테마 | 시간 |
|---|---|---|
| 1 | 테마 1: 단일 리더 복제 | 25분 |
| 2 | 테마 2: 복제 지연 문제 | 25분 |
| 3 | 테마 3: 다중 리더 복제 | 25분 |
| 4 | 테마 4: 리더 없는 복제 | 25분 |
| 5 | Q&A 및 복제 전략 선택 가이드 | 10분 |
| 총합 | 110분 |
참고자료 출처 (번호별)
| # | 참고자료 | 링크 |
|---|---|---|
| 25 | Terry Pratchett, Reaper Man (1991) | ISBN: 978-0-575-04979-6 |
| 26 | Tungsten Replicator | github.com |
| 27 | BDR 0.10.0 Documentation | bdr-project.org |
| 28 | Robert Hodges, "If You Must Deploy Multi-Master Replication, Read This First" (2012) | scale-out-blog |
| 29 | CouchDB: The Definitive Guide (O'Reilly, 2010) | ISBN: 978-0-596-15589-6 |
| 30 | AppJet/Etherpad, "EasySync Technical Manual" (2011) | github.com |
| 31 | John Day-Richter, "What's Different About the New Google Docs" (2010) | drive.googleblog.com |
| 32 | Martin Kleppmann, "A Conflict-Free Replicated JSON Datatype" (2016) | arXiv:1608.03960 |
| 33 | Frazer Clement, "Eventual Consistency – Detecting Conflicts" (2011) | messagepassing.blogspot |
| 34 | Robert Hodges, "State of the Art for MySQL Multi-Master" (Percona Live, 2013) | web.archive.org |
| 35 | John Daily, "Clocks Are Bad, or, Welcome to Distributed Systems" (2013) | riak.com |
| 36 | Riley Berton, "Is BDR in Postgres Transactional?" (2016) | sdf.org |
| 37 | DeCandia et al., "Dynamo: Amazon's Highly Available Key-Value Store" (SOSP, 2007) | allthingsdistributed.com |
| 38 | Shapiro et al., "Convergent and Commutative Replicated Data Types" (INRIA, 2011) | hal.inria.fr |
| 39 | Sam Elliott, "CRDTs: An UPDATE" (RICON West, 2013) | speakerdeck.com |
| 40 | Russell Brown, "A Bluffers Guide to CRDTs in Riak" (2013) | gist.github.com |
| 41 | Farinier et al., "Mergeable Persistent Data Structures" (JFLA, 2015) | gazagnaire.org |
| 42 | Sun & Ellis, "Operational Transformation in Real-Time Group Editors" (CSCW, 1998) | citeseerx |
| 43 | Lars Hofhansl, "HBASE-7709: Infinite Loop in Master/Master Replication" (2013) | issues.apache.org |
| 44 | Gifford, "Weighted Voting for Replicated Data" (SOSP, 1979) | cmu.edu |
| 45 | Howard et al., "Flexible Paxos: Quorum Intersection Revisited" (2016) | arXiv:1608.06696 |
| 46 | Joseph Blomstedt, "Re: Absolute Consistency" (2012) | web.archive.org |
| 47 | Joseph Blomstedt, "Bringing Consistency to Riak" (RICON West, 2012) | vimeo.com |
| 48 | Bailis et al., "Quantifying Eventual Consistency with PBS" (CACM, 2014) | bailis.org |
| 49 | Jonathan Ellis, "Modern Hinted Handoff" (DataStax, 2012) | datastax.com |
| 50 | Project Voldemort Wiki | github.com |
| 51 | Apache Cassandra Documentation | cassandra.apache.org |
| 52 | Riak Enterprise: Multi-Datacenter Replication (Basho, 2014) | web.archive.org |
| 53 | Jonathan Ellis, "Why Cassandra Doesn't Need Vector Clocks" (2013) | datastax.com |
| 54 | Lamport, "Time, Clocks, and the Ordering of Events" (CACM, 1978) | microsoft.com |
| 55 | Joel Jacobson, "Riak 2.0: Data Types" (2014) | blog.joeljacobson.com |
| 56 | Parker et al., "Detection of Mutual Inconsistency" (IEEE, 1983) | yale.edu |
| 57 | Preguiça et al., "Dotted Version Vectors" (arXiv, 2010) | arXiv:1011.5808 |
| 58 | Sean Cribbs, "A Brief History of Time in Riak" (RICON, 2014) | speakerdeck.com |
| 59 | Russell Brown, "Vector Clocks Revisited Part 2" (Basho, 2015) | riak.com |
| 60 | Carlos Baquero, "Version Vectors Are Not Vector Clocks" (2011) | haslab.wordpress.com |
| 61 | Schwarz & Mattern, "Detecting Causal Relationships in Distributed Computations" (1994) | ethz.ch |