분산 DB — 복제·샤딩·CAP·일관성 모델
한 대의 DB로 트래픽·용량·가용성을 감당 못 하는 순간이 온다. 답은 여러 대로 늘리는 것 — **복제(replication)**로 같은 데이터를 여러 노드에 두고, **샤딩(sharding)**으로 데이터를 쪼개 여러 노드에 나눈다. 그런데 여러 노드가 되는 순간 네트워크는 끊긴다는 전제 위에서 일관성과 가용성을 저울질해야 한다 — 그게 CAP다. (출처: Kleppmann Designing Data-Intensive Applications Ch 5·6·9.)
복제 — 같은 데이터를 여러 곳에
복제의 목적은 가용성(한 대 죽어도 서비스)·읽기 확장(읽기를 여러 복제본에 분산)·지역 지연 감소다. 가장 흔한 형태가 리더-팔로워(leader-follower) — 쓰기는 리더 한 곳, 읽기는 팔로워들로 분산하고, 리더의 변경을 팔로워로 *복제 로그(WAL/binlog)*로 흘린다.
- 동기 복제 — 리더가 팔로워의 확인을 기다린 뒤 커밋. *데이터 안전(팔로워에도 있음)*하지만 느리고, 팔로워가 죽으면 쓰기가 막힐 수 있다.
- 반동기(semi-sync) — 최소 한 팔로워의 수신만 기다림(안전과 속도의 타협).
- 비동기 복제 — 리더가 기다리지 않고 커밋. 빠르지만 리더가 죽으면 아직 안 넘어간 변경이 유실될 수 있다.
- 복제 지연(replication lag) — 비동기에선 팔로워가 살짝 과거다. 방금 쓴 걸 팔로워에서 읽으면 안 보이는("내 글이 사라졌다") 현상 → 읽기 일관성 보장 필요.
PostgreSQL은 스트리밍 복제(물리)·논리 복제, MySQL은 binlog 기반 복제. 페일오버(리더 승격) 시 split-brain(리더 둘) 방지가 운영의 핵심(합의·펜싱).
샤딩 — 데이터를 쪼개 나눈다
복제는 같은 데이터를 복사할 뿐 용량·쓰기는 한 노드 한계다. **샤딩(수평 분할)**은 데이터를 샤드 키로 나눠 여러 노드에 분산해 쓰기·용량까지 확장한다.
- 샤드 키 선택이 전부 — 고르게 분산되고 대부분의 질의가 한 샤드로 가게. 잘못 고르면 핫스팟(한 샤드에 몰림)·교차 샤드 질의(여러 샤드 모아야 하는 느린 질의)가 생긴다.
- 범위 vs 해시 샤딩 — 범위(날짜)는 범위 질의에 좋지만 최신에 쏠리고, 해시는 고르지만 범위 질의가 흩어진다.
- 리밸런싱 — 노드를 늘릴 때 데이터 재분배. *일관된 해싱(consistent hashing)*으로 이동량을 최소화(단순
%N은 노드 수가 바뀌면 거의 전부 이동). - 교차 샤드 조인·트랜잭션은 비싸다 — 샤딩은 조인·분산 트랜잭션을 포기/제한하는 거래다.
CAP 정리 — 분할 앞에서 하나를 포기
분산 시스템은 셋 중 둘만 동시에 만족한다 — 일관성(Consistency)·가용성(Availability)·분할 내성(Partition tolerance).
핵심 오해를 바로잡자 — 네트워크 분할(P)은 고를 수 있는 게 아니라 언젠가 반드시 일어나는 현실이다. 그래서 실질적 선택은 *"분할이 났을 때 C와 A 중 무엇을 포기하느냐"*다. CP(일관성 우선 — 분할 시 틀린 답 대신 에러/대기)냐 AP(가용성 우선 — 분할 시 오래된 답이라도 응답, 나중에 수렴)냐. PACELC는 여기에 *"분할이 없을 땐(Else) 지연(L) vs 일관성(C)"*까지 더해 더 현실적으로 본다.
정족수(Quorum) — 겹치게 해서 최신을 본다
Dynamo 계열은 리더 없이 여러 복제본에 쓰고 읽되, **R + W > N**이면 읽기 집합과 쓰기 집합이 반드시 겹쳐 최신값을 보장한다.
N=3(복제 수), W=2(쓰기 확인), R=2(읽기 확인)
→ R+W=4 > 3 = N ✅ 읽기·쓰기가 최소 한 노드에서 겹침
→ W=2면 한 노드 죽어도 쓰기 가능(가용성), R=2도 마찬가지
W를 키우면 읽기 일관성↑·쓰기 가용성↓, R을 키우면 반대 — 튜닝 가능한 일관성이다.
일관성 모델 — 강함과 최종 사이
"일관성"은 한 점이 아니라 스펙트럼이다.
- 강한 일관성(linearizable) — 항상 최신값을 본다(한 대처럼). 비싸다(합의·동기).
- 최종 일관성(eventual) — 언젠가는 수렴. 그 사이 오래된 값을 볼 수 있다(AP 시스템).
- 중간 보장들 — 읽은 값은 뒤로 안 감(monotonic read), 자기 쓴 건 읽음(read-your-writes), 인과 일관성(causal). 복제 지연 환경에서 사용자 체감을 지키는 실용적 타협들이다.
분산 트랜잭션 — 2PC vs Saga
여러 노드/서비스에 걸친 작업을 원자적으로 묶으려면?
- 2PC(2단계 커밋) — 코디네이터가 prepare→commit. 강하지만 느리고, 코디네이터가 죽으면 참가자가 잠긴다(블로킹). 마이크로서비스에선 기피.
- Saga — 큰 작업을 로컬 트랜잭션의 연쇄로 쪼개고, 실패하면 *보상 트랜잭션(상쇄)*으로 되돌린다.
Saga는 최종 일관성을 받아들이는 대신 결합·블로킹을 피한다(오케스트레이션 = 중앙 조율 vs 코레오그래피 = 이벤트 연쇄).
한 줄 요약 — 복제는 가용성·읽기 확장(동기 안전/비동기 빠름·복제 지연), 샤딩은 쓰기·용량 확장(샤드 키가 전부·일관된 해싱). 분할은 현실이라 CP(일관성) vs AP(가용성) 중 택해야 하고, 정족수
R+W>N으로 일관성을 튜닝. 분산 트랜잭션은 *2PC(블로킹) 대신 Saga(보상)*가 현대적.
(출처: Kleppmann Designing Data-Intensive Applications Ch 5·6·7·9 / PostgreSQL — High Availability / MySQL — Replication.)