같은 데이터를 여러 노드에 복사해 두는 기법. 가용성과 읽기 확장을 얻는다.
구성 방식
| 방식 | 쓰기 | 특징 |
|---|---|---|
| 단일 리더 | 리더 한 곳만 | 가장 흔함. 충돌 없음 |
| 다중 리더 | 여러 곳 | 지역 분산에 유리, 쓰기 충돌 해결 필요 |
| 리더 없음 | 아무 노드 | 쿼럼으로 읽고 씀(Dynamo 계열) |
동기 vs 비동기
동기 복제 : 리더 → 팔로워 기록 확인 → 클라이언트에 응답
- 유실 없음. 팔로워가 느리면 쓰기 전체가 느려진다
비동기 복제: 리더 → 클라이언트에 응답 (팔로워는 나중에)
- 빠름. 리더 장애 시 아직 전달 못 한 쓰기는 유실
보통 하나만 동기, 나머지는 비동기(semi-synchronous)로 타협한다. 최소 한 곳에는 확실히 남기면서 지연은 억제하는 절충이다.
복제 지연 — 실무에서 가장 자주 만나는 문제
리더에 쓴 직후 팔로워에서 읽으면 아직 반영 전일 수 있다.
- 글 작성 (리더에 INSERT)
- 목록 화면으로 이동 (팔로워에서 SELECT)
- 내가 쓴 글이 안 보인다 ← 사용자는 "글이 날아갔다"고 느낀다
대응 세 가지
| 보장 | 방법 |
|---|---|
| read-your-writes | 쓴 직후 일정 시간은 리더에서 읽기 |
| monotonic reads | 같은 사용자는 같은 팔로워로 고정 (시간이 거꾸로 가지 않게) |
| consistent prefix | 인과 관계가 있는 쓰기는 순서를 보존 |
가장 흔한 구현은 첫 번째다 — 세션에 "방금 썼음" 표시를 두고 몇 초간 리더로 라우팅한다.
페일오버의 함정
리더가 죽어 팔로워를 승격할 때
① 유실 — 비동기 복제라면 아직 전달 못 한 쓰기가 사라진다. ② split-brain — 옛 리더가 되살아나 리더가 둘이 되면 데이터가 갈라진다. → 펜싱(fencing)이나 쿼럼으로 하나만 리더가 되도록 막아야 한다. ③ 타임아웃 설정 — 너무 짧으면 일시적 부하에 불필요한 페일오버가, 너무 길면 장애 시간이 길어진다.
읽기 분산의 한계
읽기를 팔로워로 보내면 확장되지만, 쓰기는 여전히 리더 한 대가 다 받는다. 쓰기가 한계에 닿으면 복제로는 해결되지 않는다 → 그때 샤딩을 검토한다.