데이터베이스 엔지니어링 마스터 노트 시리즈 5편. 복제가 단순한 백업이 아닌 이유, Master-Slave / Multi-Master 토폴로지, 동기 vs 비동기 복제의 일관성-성능 트레이드오프, Read Replica 설계, Replication Lag의 함정, Failover 자동화, PostgreSQL Streaming Replication 실전까지.
이 글은 데이터베이스 엔지니어링 마스터 노트 시리즈의 다섯 번째 편입니다. 4편(샤딩)이 쓰기 확장이었다면, 이번엔 읽기 확장 + 고가용성 — 복제.
복제는 단순 백업이 아닌, 읽기 부하 분산과 장애 대응의 핵심. 다만 동기·비동기 결정에서 일관성과 성능이 트레이드오프 — 이 결정이 시스템 전체 동작을 결정한다.
복제란?
한 DB의 데이터를 다른 DB 인스턴스에 복사해 동일한 데이터를 여러 노드에 유지.
Primary (쓰기)
↓ 복제
Replica 1 (읽기)
Replica 2 (읽기)
Replica 3 (읽기)
목적 3가지:
- 읽기 확장 — replica로 읽기 분산
- 고가용성 (HA) — primary 다운 시 replica로 전환
- 재해 복구 — 다른 지역 replica로 백업
Master-Slave (Primary-Replica)
가장 일반적. 한 primary가 모든 쓰기, 여러 replica가 읽기.
Application
↓ 쓰기
Primary (PostgreSQL/MySQL)
↓ binary log / WAL stream
Replica 1, 2, 3 (읽기 전용)
장점 — 단순, 충돌 없음.
단점 — primary가 SPOF (Single Point of Failure). primary 다운 = 쓰기 중단.
여기서 시험 함정이 하나 있어요. Replica는 항상 읽기 전용. 쓰기 시 primary로 보내고, 복제로 따라옴. 애플리케이션이 라우팅 책임.
Multi-Master (Multi-Primary)
여러 노드가 동시에 쓰기 가능.
Master A ⇄ Master B ⇄ Master C
↑ 모두 쓰기 가능, 양방향 복제
장점 — 쓰기도 분산. 한 노드 다운에도 다른 노드 쓰기 가능.
단점 — 충돌 처리 복잡. 같은 행을 두 노드가 동시 수정하면?
여기서 정말 중요한 시험 함정 — Multi-Master는 충돌 해결 전략 필수. Last-Write-Wins / 사용자 정의 / CRDT(특수 자료구조). PostgreSQL은 기본 Multi-Master 지원 X (BDR 같은 확장 필요), CouchDB·Cassandra는 기본 지원.
동기 vs 비동기 복제 — 핵심 트레이드오프
동기 복제 (Synchronous)
Client → Primary
Primary → Replica (대기)
Replica → ACK
Primary → Client (성공)
모든 replica가 데이터 받을 때까지 응답 보류.
장점 — 강한 일관성, 데이터 손실 X.
단점 — 느림. replica 한 대 느려도 전체 영향.
비동기 복제 (Asynchronous)
Client → Primary
Primary → Client (즉시 성공)
Primary → Replica (백그라운드 복제)
즉시 응답 후 백그라운드로 복제.
장점 — 빠름.
단점 — Primary 다운 시 데이터 손실 가능 (복제 안 된 트랜잭션).
반동기 (Semi-Synchronous)
타협안. 최소 1개 replica가 받으면 OK.
여기서 정말 중요한 시험 함정 — 비동기는 Replication Lag 발생 (수 ms ~ 수 분). 같은 사용자가 쓰기 후 즉시 읽기 시 자기 쓰기를 못 볼 수 있음. 해결 = "read-your-own-writes" 패턴 (자기 쓰기는 primary에서 읽기).
Read Replica 설계
라우팅 전략
def execute(query):
if is_write(query):
return primary.execute(query)
else:
return random.choice(replicas).execute(query)
도구:
- HAProxy / ProxySQL — 자동 라우팅
- AWS RDS Proxy / Read Endpoint
- 애플리케이션 로직 (Spring
@Transactional(readOnly=true))
일관성 레벨
| 레벨 | 의미 |
|---|---|
| Strong | 항상 primary에서 (replica 안 씀) |
| Read-Your-Writes | 자기가 쓴 후 자기 읽기는 primary |
| Eventual | 결국 일치, 잠깐 stale OK |
대부분 트랜잭션 = Strong (primary), 검색·통계 = Eventual (replica).
Replication Lag — 비동기의 함정
측정
-- PostgreSQL
SELECT now() - pg_last_xact_replay_timestamp() AS lag;
-- → 00:00:01.234 (1.2초 lag)
-- MySQL
SHOW SLAVE STATUS;
-- → Seconds_Behind_Master: 5
원인
- 대량 쓰기 (피크 시간)
- 느린 네트워크
- Replica 하드웨어 부족
- 긴 트랜잭션이 replica 차단
해결
- 모니터링 알람 (lag > 임계값)
- Replica 하드웨어 ↑
- 무거운 쿼리는 dedicated replica
- 쓰기 분산 (샤딩)
Failover — 자동화 vs 수동
Primary 다운 시 replica를 새 primary로 승격.
수동 Failover
DBA가 수동으로:
- Primary 다운 확인
- 가장 lag 적은 replica 선택
PROMOTE명령- 애플리케이션 재설정
여기서 시험 함정이 하나 있어요. 다운타임 수 분~수 시간 발생. 24/7 서비스에 부적합.
자동 Failover
도구가 자동으로:
- Patroni (PostgreSQL) — Etcd/Consul로 상태 추적
- MySQL Replication Manager / Orchestrator
- AWS RDS Multi-AZ — 60초 내 자동 전환
- AWS Aurora — 30초 내
핵심 — 합의(consensus). 정족수가 모여 새 primary 결정. (Split-Brain 방지)
Split-Brain 문제
두 노드 모두 자신이 primary로 착각 = 데이터 분기.
해결:
- Quorum — 과반 합의로만 primary 결정
- Fencing — 옛 primary 강제 차단
여기서 정말 중요한 시험 함정 — Split-Brain은 분산 시스템 최악의 시나리오. 데이터 일관성 깨짐 + 사후 수동 병합 필요. Patroni·Consul 같은 합의 도구 필수.
PostgreSQL Streaming Replication 실전
# Primary 설정 (postgresql.conf)
wal_level = replica
max_wal_senders = 10
synchronous_standby_names = '*' # 동기 복제 시
# Primary 설정 (pg_hba.conf)
host replication replicator 10.0.0.0/24 md5
# Primary에서 사용자 생성
CREATE USER replicator REPLICATION LOGIN PASSWORD 'secret';
# Replica 초기화 (base backup)
pg_basebackup -h primary_host -U replicator -D /var/lib/pgsql/data -P -R
# Replica 시작
systemctl start postgresql
# 상태 확인 (Primary에서)
SELECT * FROM pg_stat_replication;
Streaming Replication 종류
- Asynchronous (기본) — 비동기, 빠름
- Synchronous —
synchronous_standby_names설정 시 - Logical Replication — 테이블 단위 복제 (선택적)
Logical vs Physical
| 종류 | 설명 |
|---|---|
| Physical (Streaming) | WAL 그대로 복제, 같은 버전 필수 |
| Logical | 변경 사항 SQL로 복제, 다른 버전·DB 가능 |
Logical은 다른 PostgreSQL 버전 간 마이그레이션 또는 선택적 테이블 복제에 유용.
MySQL Replication
# Master 설정 (my.cnf)
server-id = 1
log-bin = mysql-bin
# Master에서 복제 사용자
CREATE USER 'repl'@'%' IDENTIFIED BY 'secret';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
# Slave 설정
server-id = 2
# Slave에서 시작
CHANGE MASTER TO
MASTER_HOST='master_host',
MASTER_USER='repl',
MASTER_PASSWORD='secret',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=0;
START SLAVE;
# 상태 확인
SHOW SLAVE STATUS\G
클라우드 매니지드 복제
AWS RDS
- Multi-AZ — 동기 복제 + 자동 failover (HA용, 읽기 X)
- Read Replica — 비동기, 읽기 분산용
- Aurora — 6개 복사본 자동 분산, 30초 failover
GCP Cloud SQL
- High Availability — 동기 standby
- Read Replicas — 비동기
Azure Database
- Geo-Replication — 글로벌 분산
여기서 시험 함정이 하나 있어요. AWS RDS Multi-AZ ≠ Read Replica. Multi-AZ는 standby (쿼리 X, HA용), Read Replica는 분점 (읽기 가능).
Cascade Replication
Primary
↓
Replica 1 (역할: 또 다른 replica의 source)
↓
Replica 2 (Replica 1으로부터 복제)
장점 — Primary 부하 ↓.
단점 — Replica 2의 lag = Primary lag + Replica 1 lag (2배).
복제 vs 백업
복제 = 실시간 동기화 (운영 데이터)
백업 = 시점 복사본 (장애 복구)
여기서 정말 중요한 시험 함정 — 복제는 백업 아님. Primary에서 잘못 DELETE → replica도 즉시 DELETE. 백업은 별도 필수 (pg_dump, mysqldump, snapshot).
시험 직전 한 번 더 — 자주 헷갈리는 함정 모음
여기까지가 5편의 핵심입니다. 시험 직전 또는 실무에서 헷갈릴 때 다시 펼쳐 볼 수 있게 압축 노트로 마무리할게요.
- 복제 = 데이터를 여러 노드에 복사
- 목적 — 읽기 확장·HA·재해 복구
- Master-Slave = primary 1 + replicas N (가장 일반적)
- Multi-Master = 여러 primary, 충돌 해결 필수
- Replica는 읽기 전용, 쓰기는 primary
- 동기 (Synchronous) = 강한 일관성, 느림
- 비동기 (Asynchronous) = 빠름, 데이터 손실 가능
- 반동기 (Semi-Sync) = 최소 1개 replica ACK
- Replication Lag = 비동기의 함정, 수 ms ~ 수 분
- Read-Your-Writes = 자기 쓰기는 primary 읽기
- 일관성 레벨 — Strong / Read-Your-Writes / Eventual
- 라우팅 — HAProxy·ProxySQL·RDS Proxy·앱 로직
- Failover = primary 다운 시 replica 승격
- 수동 = 다운타임 큼 / 자동 = 분 이내
- Split-Brain = 두 노드 모두 primary, 데이터 분기 최악
- 해결 = Quorum(과반 합의) + Fencing(옛 primary 차단)
- 도구 — Patroni·Orchestrator·Consul
- PostgreSQL — Streaming Replication (WAL 기반)
- Physical vs Logical Replication
- Logical = 다른 버전·선택적 테이블
- AWS RDS Multi-AZ ≠ Read Replica
- Multi-AZ = HA standby (쿼리 X) / Read Replica = 읽기 가능
- Aurora = 6 복사본 자동, 30초 failover
- Cascade Replication = replica의 replica, lag 누적
- 복제 ≠ 백업 — DELETE 실수 시 모두 사라짐
- 백업 별도 필수 (pg_dump·mysqldump·snapshot)
시리즈 다른 편
- 1편 — ACID·트랜잭션
- 2편 — 인덱싱
- 3편 — 파티셔닝
- 4편 — 샤딩
- 5편 — 복제 (현재 글)
- 6편 — 동시성 제어
- 7편 — 내부 구조
- 8편 — 고급 주제
공식 문서: PostgreSQL Streaming Replication 에서 더 깊이.
다음 글(6편)에서는 동시성 제어 — Locking·MVCC·Deadlock·Phantom Read까지 1편 ACID에서 살짝 본 격리 수준의 구현을 풀어 갑니다.