PostgreSQL

PostgreSQL: 스트리밍 복제 지연

dewstream 2025. 11. 12. 08:00
728x90

※ PostgreSQL: Streaming-replication Lag.

 

안녕하세요. 듀스트림입니다.

 

오늘 포스팅은 PostgreSQL에서 스트리밍 복제 지연 발생 시 분석 방법에 대한 내용입니다.

 

결론부터 말씀드리면 주로 발생하는 지연 원인은 경험상 아래 정도가 있는 것 같습니다.

  1. 대부분 비동기 복제 정책 문제 (95% 이상)
  2. 배치, Autovacuum, 인덱스 재작성 등 피크 타임에 WAL 폭증
  3. 너무 잦은 체크포인트
  4. Primary와 Standby의 스토리지 차이(NVME, SSD, HDD)
  5. 네트워크 지터

1. 어디에서 느린건지 구분

▸ 복제 동작은 크게 아래 3단계로 볼 수 있습니다:

WAL 생성 → 전송/수신 → 재생(리플레이)

→ 이 중 어디가 느린지에 따라 원인이 갈립니다.

 

1.1 Primary에서 확인

-- 세션별 전송/기록/재생 지연 확인
SELECT pid, application_name, state,
       write_lag,  -- 보낸 WAL을 스탠바이가 'write'까지 걸린 시간
       flush_lag,  -- 'flush'까지 걸린 시간
       replay_lag, -- 'replay'(적용)까지 걸린 시간
       sent_lsn, write_lsn, flush_lsn, replay_lsn,
       sync_state  -- async / sync / quorum ...
FROM pg_stat_replication;

→ write_lag/flush_lag가 크면 전송·수신·디스크쓰기 문제, replay_lag만 크면 스탠바이 리플레이 병목일 가능성이 큽니다.

 

 

27.2. The Cumulative Statistics System

27.2. The Cumulative Statistics System # 27.2.1. Statistics Collection Configuration 27.2.2. Viewing Statistics 27.2.3. pg_stat_activity 27.2.4. pg_stat_replication 27.2.5. pg_stat_replication_slots 27.2.6. pg_stat_wal_receiver …

www.postgresql.org


1.2 Standby에서 확인

-- 스탠바이가 얼마만큼 따라잡았는지(적용되었는지)
-- 시간 지연
SELECT now() - pg_last_xact_replay_timestamp() AS apply_delay;

→ 참고로 이 함수는 프라이머리가 한가할 때는 "지연처럼" 보일 수 있어 해석에 주의해야 합니다. (거래가 드물면 최근 커밋 타임스탬프가 오래되어 지연으로 오인될 수 있음)

 

-- WAL 수신 상태(스탠바이)
SELECT * FROM pg_stat_wal_receiver;

→ 여기서 last_msg_send_time / last_msg_receipt_time, latest_end_lsn 등을 보면 네트워크/수신 측 상태를 파악할 수 있습니다.


2. 패턴별 원인과 해결 가이드

2.1 write_lag/flush_lag ↑ (전송·수신·디스크 쓰기 측 병목)

▸ 가능한 원인

  • 네트워크 지터/패킷 손실/MTU 불일치
  • 스탠바이 디스크 쓰기 지연(저속 스토리지, flush 대기, 체크포인트 타이밍 겹침)
  • WAL 폭증(대량 DML/Autovacuum 대규모 청소/대량 인덱스 재작성 등)

 

▸ 점검/개선

  • 네트워크: 인터페이스 에러/재전송, MTU, TCP offload, RTT 모니터링
  • 스토리지: 스탠바이 I/O 대기 시간, 체크포인트 설정(아래), WAL 파일 flush 대기
  • 체크포인트/ WAL 양 줄이기:
    • checkpoint_timeout, max_wal_size, checkpoint_completion_target 재조정
    • 불필요한 대량 변경 피크 분산, Autovacuum 튜닝(테이블별 aggressive vacuum 방지)
  • 프라이머리 WAL 보존: (PG13+) wal_keep_size 또는 (구버전) wal_keep_segments 적정값 설정으로 재전송·재요청 부담 완화 (명칭/의미 변경 주의)

2.2 replay_lag만 ↑ (스탠바이 적용이 느린 경우)

▸ 가능한 원인

  • 스탠바이 단일 스레드 리플레이가 I/O 바운드 (대량 업데이트/인덱스 유지비용/FPW 등)
  • 스탠바이에서 동시에 읽기 트래픽이 많아 리플레이와 I/O 경합
  • 체크포인트 직후 더 많은 더티 페이지 쓰기로 리플레이가 밀림

 

▸ 점검/개선

  • 스탠바이 I/O/CPU 모니터링으로 리플레이가 I/O 바운드인지 확인
  • 스토리지 성능 개선 또는 스탠바이에 리더 전용 트래픽을 분산
  • 체크포인트/Autovacuum/인덱스 유지 비용이 리플레이와 충돌하지 않도록 스케줄·파라미터 조정

2.3 프라이머리가 항상 바쁜데 시간 기반 지연 지표가 크게 보이는 경우

  • pg_last_xact_replay_timestamp() 기반 시간 차이는 프라이머리가 유휴일 때도 지연처럼 보일 수 있으니, LSN 차이 및 pg_stat_replication의 _lag 칼럼을 함께 확인보시길 바랍니다.

2.4 비동기 복제 구성이라 의도된 지연이 발생

  • synchronous_commit = off/remote_write/on/remote_apply 및 synchronous_standby_names 값에 따라 커밋 대기가 달라집니다.
  • 완전 동기(특히 remote_apply) 로 갈수록 프라이머리 TPS는 떨어지지만, 스탠바이 가시성 지연은 사실상 0에 수렴합니다(대기 비용을 프라이머리로 전가).

3. 원인 분리 체크리스트

3.1 세션별 lag 스냅샷

SELECT now() AS ts, application_name, state,
       write_lag, flush_lag, replay_lag,
       sent_lsn, write_lsn, flush_lsn, replay_lsn
FROM pg_stat_replication;

→ 1분 간격으로 몇 번 수집해 패턴을 봅니다. write/flush가 튀면 전송·수신 측, replay만 튀면 적용 측 이슈.


3.2 스탠바이 수신 상태

SELECT now() AS ts, status, conninfo,
       last_msg_send_time, last_msg_receipt_time, latest_end_lsn
FROM pg_stat_wal_receiver;

→ last_msg_* 차이가 크면 네트워크/수신 지연 신호입니다.


3.3 시간 기반 지연 (적용 기준)

SELECT now() - pg_last_xact_replay_timestamp() AS apply_delay;

→ 이 값은 해석에 주의 해야합니다(프라이머리 유휴 시 오판 가능). 반드시 LSN 지표와 함께 체크하시길 바랍니다.


3.4 체크포인트 영향

체크포인트 직후 replay_lag가 급증하면 checkpoint_timeout / max_wal_size / checkpoint_completion_target 재조정을 고려하시길 바랍니다.


3.5 WAL 보존/회수

Primary의 wal_keep_size(또는 구버전 wal_keep_segments)가 너무 작아 잦은 재요청·재전송이 생기지 않는지 점검이 필요합니다.


3.6 구성 정책 확인

동기/비동기, synchronous_standby_names, synchronous_commit 정책이 의도한 RPO/RTO와 맞는지 재점검이 필요합니다.
(엄격한 실시간 가시성이 필요하면 remote_apply 고려)

※ 아래와 같이 설정하면 COMMIT 시 Standby 적용까지 기다립니다. (대신 Primary의 대기시간이 증가합니다.)
synchronous_standby_names = 'FIRST 1 (node2, node3, ...)'
synchronous_commit = remote_apply

오늘은 여기까지~

 

 

 

728x90

'PostgreSQL' 카테고리의 다른 글

PostgreSQL: SELECT 효율 분석  (0) 2025.11.21
PostgreSQL: DISTINCT ON  (0) 2025.11.19
PostgreSQL: never executed  (0) 2025.11.10
PostgreSQL: ctid  (0) 2025.11.07
PostgreSQL: Heap Table Structure  (0) 2025.11.05