3.4 pg_stat_statements
Database 전체 TPS가 늘었다는 사실만으로 어떤 query가 부하를 만들었는지 알 수 없습니다. pg_stat_statements는 정규화된 query별 호출 횟수, 총 실행 시간, 처리 row, block I/O 시간을 누적합니다. PostgreSQL Exporter의 stat_statements collector는 이 정보를 Prometheus metric으로 변환합니다.
PostgreSQL 설정
Extension은 shared preload가 필요합니다.
shared_preload_libraries = 'pg_stat_statements'
compute_query_id = auto
track_io_timing = on
재시작 후 database마다 extension을 만듭니다.
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
Exporter role의 search_path에는 pg_stat_statements를 설치한 schema가 포함되어야 합니다. Collector가 extension view를 schema 없이 조회하기 때문입니다.
track_io_timing은 I/O timing 수집 비용이 있으므로 환경에서 측정한 뒤 사용합니다. 최신 Linux에서는 대체로 작지만 workload와 platform에 따라 확인해야 합니다.
Collector 활성화
postgres_exporter \
--collector.stat_statements \
--collector.stat_statements.limit=100
Collector가 만드는 주요 metric은 다음과 같습니다.
| Metric | Label | 의미 |
|---|---|---|
pg_stat_statements_calls_total | user/datname/queryid | 실행 횟수 누계 |
pg_stat_statements_seconds_total | user/datname/queryid | 총 실행 시간 |
pg_stat_statements_rows_total | user/datname/queryid | 처리 row 누계 |
pg_stat_statements_block_read_seconds_total | user/datname/queryid | block read 시간 |
pg_stat_statements_block_write_seconds_total | user/datname/queryid | block write 시간 |
총부하가 큰 query
최근 5분 동안 DB 시간을 가장 많이 소비한 query ID를 찾습니다.
topk(10,
sum by (instance, datname, queryid) (
rate(pg_stat_statements_seconds_total[5m])
)
)
이 값은 초당 소비한 database execution seconds에 가깝습니다. 병렬 실행과 여러 session 때문에 합계가 wall-clock 1초를 넘기도 합니다.
평균 실행 시간
총 실행 시간 증가율을 호출 증가율로 나눕니다.
sum by (instance, datname, queryid) (
rate(pg_stat_statements_seconds_total[5m])
)
/
clamp_min(
sum by (instance, datname, queryid) (
rate(pg_stat_statements_calls_total[5m])
),
0.001
)
평균만 보면 한 번의 극단적 지연이나 tail latency를 숨길 수 있습니다. pg_stat_statements는 histogram이 아니므로 p95/p99를 제공하지 않습니다. 사용자 latency 분포는 애플리케이션 metric이나 trace에서 확인합니다.
SQL 원문을 label에 넣지 않는다
--collector.stat_statements.include_query는 query text mapping metric을 추가합니다. SQL은 길고 값이 다양하며 개인정보나 literal을 포함할 수 있습니다. 운영에서는 기본 비활성 상태를 유지하고, query ID를 다음 SQL로 원문과 연결합니다.
SELECT queryid,
calls,
total_exec_time,
mean_exec_time,
rows,
query
FROM pg_stat_statements
WHERE queryid = :queryid;
Exporter source도 이 collector를 기본 비활성화합니다. Busy server에서 query마다 series가 생겨 비용이 커질 수 있기 때문입니다.
Limit과 reset
Collector는 총 실행 시간 상위 statement를 제한된 수만 내보냅니다. 새로운 query가 top 목록에 들어오면 기존 series가 사라질 수 있으므로, 장기 ranking 데이터베이스처럼 사용하지 않습니다.
pg_stat_statements_reset()을 실행하면 counter가 reset됩니다. Prometheus rate()는 reset을 처리하지만 장기 비교에는 reset 시각을 annotation이나 운영 기록으로 남깁니다.
언제 켜는가
다음 조건을 만족할 때 활성화합니다.
- query ID 수와 예상 series를 계산함
- statement limit을 정함
- SQL 원문 label을 비활성화함
- scrape duration과 sample 수 변화를 관찰함
pg_stat_statements.max와 tracking 정책을 검토함
참고: PostgreSQL pg_stat_statements, Exporter stat_statements collector