8.4 정기 점검 체크리스트
지금까지의 Part I~VIII를 정리하면, 운영자가 주기적으로 봐야 하는 항목이 추려집니다. 일·주·월·분기 단위 점검 SQL을 한 곳에 모은 체크리스트입니다. 자동화의 출발점으로 사용합니다.
일 단위 (매일 / 알람 권장)
1. 활성 long transaction
SELECT pid, usename, datname, state, xact_start,
now() - xact_start AS age, query
FROM pg_stat_activity
WHERE state IN ('active','idle in transaction','idle in transaction (aborted)')
AND xact_start < now() - interval '5 minutes'
ORDER BY xact_start;5분 넘는 트랜잭션 = 알람을 받습니다. xmin horizon이 잡혀 vacuum이 막힙니다.
2. 락 대기 그래프
SELECT bl.pid AS blocked, bl.query AS blocked_query,
kl.pid AS blocking, kl.query AS blocking_query
FROM pg_stat_activity bl
JOIN LATERAL (
SELECT * FROM pg_stat_activity WHERE pid = ANY(pg_blocking_pids(bl.pid))
) kl ON true
WHERE cardinality(pg_blocking_pids(bl.pid)) > 0;비어 있어야 정상. 비어있지 않으면 즉시 확인합니다.
3. replication slot 정체
SELECT slot_name, slot_type, active,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS lag,
wal_status
FROM pg_replication_slots
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC NULLS LAST;lag가 GB 단위로 자라거나 wal_status = 'lost'면 즉시 대응합니다. (12장 복제 참고)
4. errors in log (외부 로그 시스템에서)
ERROR, FATAL, PANIC 줄. 특히 deadlock detected, out of memory, could not extend file, database is being recovered 등.
주 단위
1. XID wraparound 안전 마진
SELECT datname,
age(datfrozenxid) AS xid_age,
round(age(datfrozenxid)::numeric / 2147483648, 3) AS used_ratio
FROM pg_database
ORDER BY age(datfrozenxid) DESC;used_ratio가 0.5 (10억) 이상이면 주의. 0.7 이상이면 즉시 대응합니다.
2. dead tuple 누적
SELECT relname, n_live_tup, n_dead_tup,
round(100.0 * n_dead_tup / nullif(n_live_tup, 0), 1) AS dead_pct,
last_vacuum, last_autovacuum
FROM pg_stat_user_tables
WHERE n_dead_tup > 10000
ORDER BY dead_pct DESC NULLS LAST
LIMIT 20;dead_pct > 20% 테이블이 자주 보이면 autovacuum 튜닝 검토합니다.
3. 미사용 인덱스
SELECT s.relname AS table, s.indexrelname AS index,
pg_size_pretty(pg_relation_size(s.indexrelid)) AS size, s.idx_scan
FROM pg_stat_user_indexes s
JOIN pg_index i ON s.indexrelid = i.indexrelid
WHERE s.idx_scan = 0 AND NOT i.indisunique
AND pg_relation_size(s.indexrelid) > 10*1024*1024
ORDER BY pg_relation_size(s.indexrelid) DESC;idx_scan = 0이고 크면 drop 후보입니다. 단, 최근 추가된 인덱스나 주말 배치만 쓰는 인덱스는 예외.
4. 느린 쿼리 top
SELECT round(mean_exec_time::numeric, 1) AS avg_ms,
calls,
round(total_exec_time::numeric / 1000, 1) AS total_sec,
LEFT(query, 80) AS query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;pg_stat_statements를 활성한 클러스터의 표준입니다. total_exec_time(전체 부하)이 큰 쿼리부터.
월 단위
1. 인덱스 BLOAT
SELECT i.relname AS index,
pg_size_pretty(pg_relation_size(i.oid)) AS size,
round(s.avg_leaf_density, 1) AS density
FROM pg_class i
JOIN pgstatindex(i.oid) s ON true
WHERE i.relkind = 'i' AND pg_relation_size(i.oid) > 100*1024*1024
ORDER BY density LIMIT 10;density < 70인 큰 인덱스 = REINDEX CONCURRENTLY 후보입니다.
2. 테이블 크기 추세
SELECT schemaname, relname,
pg_size_pretty(pg_total_relation_size(relid)) AS total,
pg_size_pretty(pg_relation_size(relid)) AS table,
pg_size_pretty(pg_indexes_size(relid)) AS indexes,
pg_size_pretty(pg_total_relation_size(relid) - pg_relation_size(relid)) AS toast_idx
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 20;월간 추이 그래프로 그려 두면 용량 계획 자료. 갑작스러운 증가 = 알람을 받습니다.
3. 통계 신선도
SELECT relname, n_mod_since_analyze, last_analyze, last_autoanalyze
FROM pg_stat_user_tables
ORDER BY GREATEST(last_analyze, last_autoanalyze) NULLS FIRST
LIMIT 10;last_*가 한 달 이상 안 갱신된 테이블 = scale_factor 점검 또는 명시 ANALYZE.
4. autovacuum 워커 활동
SELECT pid, datname, relid::regclass, query
FROM pg_stat_activity
WHERE backend_type = 'autovacuum worker';월 단위 통계: 일정 시간대에 autovacuum이 얼마나 동시에 도는지. autovacuum_max_workers 부족이면 동시에 다 차 있을 것.
5. WAL 생성량
SELECT wal_records, wal_fpi, wal_bytes, wal_buffers_full, stats_reset
FROM pg_stat_wal; -- PG 14+월간 WAL 생성량은 아카이브 저장소 용량 계획과 복제 슬롯 보존 정책의 입력합니다.
분기·반기
1. REINDEX·pg_repack
월 점검에서 BLOAT 누적된 인덱스·테이블에 대해 분기 정비. (8.3)
2. 파티션 retention 정책 점검
pg_partman의 retention 결정이 여전히 정책에 맞는지 — 보존 기간 변경 검토합니다.
3. 메이저 업그레이드 계획
각 메이저는 5년 지원 (1.1). EOL 6개월 전엔 업그레이드 일정 잡기.
4. PgBackRest·Barman 복구 훈련
백업이 실제로 복원 가능한지 분기마다 검증합니다. (Part XI)
5. 보안 패치 / 마이너 업그레이드
마이너 패치는 분기마다 출시. 점검 시간 잡고 업그레이드 (Part XVIII).
알람 임계 기본
| 항목 | 임계 |
|---|---|
| Long transaction | 5분 |
| Replication lag | 1GB 또는 1분 |
idle in transaction | 5분 |
| XID wraparound | xid_age > 1억(WARN), 1.5억(CRIT) |
| 디스크 사용률 | 80% (WARN), 90% (CRIT) |
| Dead tuple 비율 | 20% |
| Connection 사용률 | 80% |
| Autovacuum 워커 모두 사용 중 | 5분 이상 |
pg_stat_archiver last_failed_time | 5분 |
자동화 — Prometheus + Grafana
운영 표준은 점검 SQL을 메트릭으로 노출 + Grafana 대시보드.
| 도구 | 역할 |
|---|---|
postgres_exporter | pg_stat_*·통계 함수를 Prometheus 메트릭으로 |
node_exporter | OS 메트릭 (CPU, 디스크 IO, 메모리) |
| Grafana | 대시보드, 알람 정책 |
| Alertmanager / OpsGenie | 알람 라우팅 |
자세한 모니터링 셋업은 Part X 10.7~10.8.
정리
- 일 단위: long transaction, 락, replication slot, error log
- 주 단위: XID wraparound, dead tuple, 미사용 인덱스, 슬로우 쿼리
- 월 단위: 인덱스 BLOAT, 테이블 크기 추세, 통계 신선도, autovacuum 활동, WAL 생성
- 분기·반기: REINDEX/pg_repack, retention 검토, 메이저 업그레이드 계획, 복구 훈련
- 자동화는 postgres_exporter + Grafana + Alertmanager가 표준
Part VIII 유지보수가 끝났습니다. 다음 Part IX에서는 인증·보안·권한을 봅니다.