PostgreSQL 교재 · 21편 / 24편

스트리밍 복제 — Primary/Standby 구축

실시간 복제와 핫 스탠바이. 장애 복구의 표준 아키텍처.

고급읽는 시간 8분2026-05-17
Primary 가 WAL 을 Standby 로 스트리밍하는 복제 아키텍처 도식

한 대만 굴리면 죽을 때 끝납니다. 운영 DB 는 거의 항상 2대 이상 — Primary + Standby. Primary 가 받은 쓰기를 WAL 로 Standby 에 실시간 전송, Primary 가 죽으면 Standby 가 Primary 가 됩니다. 21편은 그 표준 아키텍처를 처음부터 끝까지.

왜 복제? — 3가지 이유

  • 고가용성(HA) — Primary 죽어도 Standby 가 즉시 대체.
  • 읽기 분산 — Standby 에 SELECT 보내 부하 분산 (hot standby).
  • 지리적 분산 — 다른 리전에 Standby 두어 재해 대비.

WAL 기반 복제 — 한 줄 원리

WAL(Write-Ahead Log). Postgres 는 모든 변경을 디스크 데이터 파일에 쓰기 전에 WAL 에 먼저 기록 (durability 보장). 복제는 그 WAL 을 Standby 에 그대로 전달해 같은 변경을 다시 적용. 그래서 두 노드의 상태가 동일.

Primary 설정 — postgresql.conf

# Primary
wal_level = replica
max_wal_senders = 10          # 최대 standby 수 + 여유
wal_keep_size = 1GB           # standby 가 따라잡을 시간 여유
synchronous_commit = on       # 또는 remote_apply (동기 시)

# pg_hba.conf — replicator 사용자 허용
host  replication  replicator  10.0.0.0/24  scram-sha-256
-- Primary 에서 replicator 역할 생성
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD '...';

-- replication slot 만들기 (권장)
SELECT pg_create_physical_replication_slot('standby_1');
-- WAL 이 standby 가 받기 전까지는 삭제되지 않음 → 안전

Standby 부트스트랩 — pg_basebackup

# Standby 노드에서, 빈 디렉터리에
sudo systemctl stop postgresql
sudo -u postgres rm -rf /var/lib/postgresql/16/main

sudo -u postgres pg_basebackup \
  -h primary.example.com \
  -U replicator \
  -D /var/lib/postgresql/16/main \
  -Fp -Xs -P -R \
  -S standby_1

# -R : 자동으로 standby.signal + primary_conninfo 생성
# -S standby_1 : 미리 만든 replication slot 연결

sudo systemctl start postgresql

postgresql.auto.conf 자동 생성 결과

# pg_basebackup -R 가 만들어 줌
primary_conninfo = 'host=primary.example.com user=replicator password=... port=5432'
primary_slot_name = 'standby_1'

# standby.signal 빈 파일이 있으면 Postgres 가 standby 모드로 시작

복제 상태 확인

-- Primary 에서
SELECT pid, usename, application_name, client_addr,
       state, sync_state, sent_lsn, write_lsn, flush_lsn, replay_lsn,
       pg_size_pretty(pg_wal_lsn_diff(sent_lsn, replay_lsn)) AS lag
FROM   pg_stat_replication;

-- Standby 에서
SELECT pg_is_in_recovery();    -- true 면 standby
SELECT pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();

hot standby — 읽기 분산

# Standby 의 postgresql.conf
hot_standby = on              # standby 에서 SELECT 허용 (PG 11+ 는 기본)
max_standby_streaming_delay = 30s   # 충돌 시 standby 가 대기할 최대 시간
-- 애플리케이션 — 읽기는 standby, 쓰기는 primary
const writeDb = new Pool({ host: "primary.example.com" });
const readDb  = new Pool({ host: "standby.example.com" });

await writeDb.query("INSERT ...");   // primary
await readDb.query("SELECT ...");    // standby (살짝 옛 데이터 가능)

읽기 일관성 함정. Standby 는 보통 수십 ms 뒤처짐. "방금 INSERT 한 것을 같은 요청에서 SELECT" 면 standby 에 없을 수도. 본인이 방금 쓴 데이터는 primary 에서 읽기가 안전한 패턴 (read-your-writes).

동기 vs 비동기

비동기 (기본)동기
commit 응답primary local 디스크standby 도 받음
데이터 손실 위험primary 갑자기 죽으면 마지막 몇 ms 손실 가능없음
쓰기 속도빠름네트워크 RT 만큼 느림
설정기본synchronous_standby_names = '*'
# 동기 복제
synchronous_commit = on
synchronous_standby_names = 'ANY 1 (s1, s2, s3)'  -- 셋 중 하나만 응답하면 OK

# 가장 강한 — remote_apply (standby 가 replay 까지 완료)
synchronous_commit = remote_apply

failover — Primary 죽었을 때

# Standby 를 primary 로 승격
sudo -u postgres pg_ctl promote -D /var/lib/postgresql/16/main

# 또는 SQL (PG 12+)
SELECT pg_promote();

# 결과 — standby.signal 제거, 쓰기 받기 시작

실전 failover. 수동은 위험·느림. patroni + etcd(또는 consul) 가 표준 — 자동 감지 + 안전한 승격 + split-brain 방지. 클라우드는 RDS·Aurora 가 같은 일을 관리형으로.

아키텍처 레퍼런스

# 작은 규모
[Primary] --(WAL stream)--> [Standby]
    ^                              |
    |                              v
  App writes                  App reads (hot standby)

# 중간 규모 (자동 failover)
[Patroni cluster: Primary + Standby x N]
     ^                       ^
     |                       |
  [HAProxy or pgBouncer for connection routing]
     ^
     |
   [App]

# 대규모 (관리형 추천)
[AWS RDS/Aurora] — 자동 백업·자동 failover·read replica

logical replication — 부분 복제

-- 옵션 — 전체가 아닌 특정 테이블만 복제
-- PG 10+ 표준

-- Primary
ALTER SYSTEM SET wal_level = 'logical';
CREATE PUBLICATION my_pub FOR TABLE users, orders;

-- Subscriber
CREATE SUBSCRIPTION my_sub
  CONNECTION 'host=primary user=...'
  PUBLICATION my_pub;

스트리밍 복제는 전체 클러스터 복제, logical 은 테이블 단위·다른 메이저 버전 간·다른 스키마 변환 가능. 마이그레이션·CDC 에 자주 사용.

모니터링 체크리스트

  • pg_stat_replicationlag — 1초 이상이면 경고.
  • Standby 의 pg_last_wal_replay_lsn 정지 — 어딘가 막혔음.
  • replication slot 의 active = false 가 길면 — WAL 이 쌓여 디스크 폭주.
  • 주기적 failover 훈련 — 진짜 사고 났을 때 당황 안 함.

22편 — 파티셔닝 (RANGE·LIST·HASH)

큰 테이블을 잘게 — 시계열·다국가 데이터의 표준.

📚 PostgreSQL 배우기 교재
이전: 20편 백업 · 현재: 21편 (고급) · 다음 → 22편 파티셔닝 · 진행: 21/24

© 2026 주나이테크(주) @JUNAITECH