본문으로 건너뛰기
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 폭증