본문으로 건너뛰기
15.5 복제 지연·끊김

15.5 복제 지연·끊김

복제(streaming·logical) 사고는 서서히 자라다 갑자기 터지는 패턴이 흔합니다. lag 모니터링·즉시 대응·재구축 절차를 정리합니다.

lag 측정 — primary 측

SELECT application_name, client_addr, state,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn))    AS sent_lag,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), write_lsn))   AS write_lag,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), flush_lsn))   AS flush_lag,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn))  AS replay_lag,
       write_lag, flush_lag, replay_lag,
       sync_state
  FROM pg_stat_replication;
단계의미
sent_lagprimary가 못 보낸 양 — 네트워크 또는 standby 수신 못 함
write_lagstandby가 받았지만 안 씀
flush_lag안 fsync — standby 디스크 느림
replay_lag받았지만 적용 못 함 — single big tx, 쿼리 충돌

lag 원인별 진단

1. sent_lag 큼 → 네트워크 / standby down

# 네트워크
ping standby.example.com
# 또는 standby 호스트 자체 응답 안 함

대응: 네트워크 복구합니다. 오랜 시간 끊겨 WAL 잘림 위험 → slot으로 보호 또는 재구축.

2. flush_lag 큼 → standby 디스크 느림

# standby 호스트에서
iostat -xz 1 5
# %util, await 점검

대응: 디스크 IO 한계 — 스토리지 점검 또는 인스턴스 upgrade.

3. replay_lag 큼 → single big tx 또는 query conflict

-- standby 측에서 진단
SELECT pid, query, wait_event_type, wait_event,
       backend_xmin, now() - xact_start AS age
  FROM pg_stat_activity
 WHERE state = 'active';
원인대응
큰 트랜잭션 (primary의 GB 단위 UPDATE)기다림
query conflict (12.3)max_standby_streaming_delay 조정
hot_standby_feedback 부재인지
disk IO 한계같음

standby 끊김

-- primary
SELECT count(*) FROM pg_stat_replication WHERE state = 'streaming';
-- 평소보다 적으면 누군가 끊김

-- 어떤 slot이 inactive
SELECT slot_name, active, restart_lsn
  FROM pg_replication_slots
 WHERE NOT active;

standby 재연결

standby에서:

# 로그 확인
tail -100 /var/lib/pgsql/17/data/log/postgresql-*.log

흔한 메시지:

메시지원인
requested WAL segment ... has already been removedprimary pg_wal 잘림 — slot 없으면 발생
could not connect네트워크 또는 primary down
authentication failedpg_hba·비밀번호 변경
replication terminated by primary serverprimary 정지

WAL 잘려서 재구축 필요

FATAL:  could not receive data from WAL stream: ERROR:  requested WAL segment ... has already been removed

slot 없는 standby가 오래 끊기면 발생합니다. 재구축:

sudo systemctl stop postgresql-17
sudo rm -rf /var/lib/pgsql/17/data/*
sudo -u postgres pg_basebackup -h primary -U repl_user \
  -D /var/lib/pgsql/17/data -X stream -P -R --slot=standby1
sudo systemctl start postgresql-17

큰 클러스터는 수 시간 걸림 — 평소 슬롯 사용 + max_slot_wal_keep_size로 예방.

logical replication 사고

subscription 멈춤

-- subscriber 측
SELECT subname, received_lsn, latest_end_lsn, latest_end_time
  FROM pg_stat_subscription;

SELECT * FROM pg_stat_subscription_stats;
-- apply_error_count, sync_error_count 증가하면 충돌

흔한 사고:

원인진단
primary key 충돌subscriber에 같은 PK row가 이미
DDL 비동기publisher만 ALTER, subscriber에 컬럼 없음
sequence 갱신 안 됨subscriber에 직접 INSERT 시 충돌
권한 부족subscriber 사용자 권한

충돌 후 복구

-- subscriber에서 충돌 row 정리 후
ALTER SUBSCRIPTION sub_orders ENABLE;

pg_replication_origin_advance로 LSN 강제 진행도 가능 — 일부 변경 스킵. 데이터 일관성 위험, 신중히 진행합니다.

sync replication에서 standby 죽음

-- primary 트랜잭션이 영원히 commit 안 됨

원인: synchronous_standby_names에 지정된 standby가 모두 응답 안 합니다.

대응:

-- 임시 — fallback
ALTER SYSTEM SET synchronous_standby_names = '';
SELECT pg_reload_conf();

비동기로 일시 전환 → standby 복구 → 다시 sync 복원. quorum으로 운영(ANY 2 (s1,s2,s3))하면 한 대 죽어도 진행 (12.1).

hot_standby_feedback과 BLOAT

hot_standby_feedback = on인데 standby의 긴 트랜잭션이 있으면 primary vacuum 차단합니다.

-- primary에서
SELECT * FROM pg_stat_replication;
-- backend_xmin 컬럼 — 가장 작은 xmin이 vacuum horizon

긴 분석 쿼리가 standby에 떠 있는지 확인합니다.

logical slot xmin

SELECT slot_name, xmin, catalog_xmin, restart_lsn,
       pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS lag
  FROM pg_replication_slots
 WHERE slot_type = 'logical';

catalog_xmin이 진행 안 되면 system catalog vacuum 멈춤 → 카탈로그 BLOAT → 모든 쿼리 느려집니다.

대응: subscriber의 적용 상태 확인합니다. 죽어 있으면 죽은 slot 정리합니다.

자동 모니터링 알람

지표WARNCRIT
replay_lag1초10초
sent_lag100MB1GB
slot inactive즉시
sync_state = potential (sync standby 없음)즉시
subscription error즉시
catalog_xmin stuck시간 단위

정리

  • streaming lag 4단계: sent / write / flush / replay
  • 가장 흔한 원인: network·standby IO·big tx·query conflict
  • WAL 잘리면 standby 재구축 — slot 사용으로 예방
  • sync replication은 quorum으로 한 대 죽음 견딤
  • logical replication 사고는 DDL 동기화·PK 충돌이 흔함
  • catalog_xmin stuck = 카탈로그 BLOAT 폭증

다음 절(15.6)에서는 가장 무서운 사고 — corruption 대응을 봅니다.