PostgreSQL 캐시 히트율 최적화와 모니터링
PostgreSQL의 버퍼 캐시 원리와 주요 설정, 모니터링 쿼리, 실무 적용 우선순위를 정리한 캐시 히트율 최적화 전략
목차
개요
데이터베이스 성능 개선에서 캐시 히트율은 비용과 직결되는 핵심 지표다. PostgreSQL은 공유 버퍼(shared_buffers)와 운영체제 페이지 캐시가 함께 동작한다. 좋은 히트율은 디스크 I/O 감소와 응답 시간 단축으로 이어진다. 본문은 postgres cache hit 개선을 위한 설정과 모니터링 방법을 초보자도 이해하기 쉬운 흐름으로 정리한다.
기초 개념
버퍼와 히트율의 의미
PostgreSQL은 디스크 블록을 메모리에 캐시해 재사용한다. 블록이 이미 메모리에 있으면 블록 히트(blks_hit)가 증가하고, 없으면 블록 읽기(blks_read)가 발생한다. 히트율은 다음과 같이 계산된다.
SELECT sum(blks_hit) AS hits,
sum(blks_read) AS reads,
CASE WHEN sum(blks_hit)+sum(blks_read)=0
THEN NULL
ELSE round(100.0 * sum(blks_hit) / (sum(blks_hit)+sum(blks_read)),2)
END AS hit_ratio
FROM pg_stat_database;
OS 캐시와 effective_cache_size의 관계
effective_cache_size 설정은 PostgreSQL의 쿼리 플래너가 사용 가능한 OS 캐시 및 shared_buffers를 추정하도록 돕는다. 실제 캐시 크기를 바꾸는 값은 아니며, 플래너의 비용 추정에 영향을 줘 인덱스 사용 여부 등에 관여한다. 따라서 effective_cache_size 설정 postgres 문맥에서 적절히 조정하면 쿼리 계획이 개선되어 간접적으로 cache hit 개선 효과가 나타난다.
모니터링 도구와 쿼리
pg_stat_statements와 pg_stat_database
pg_stat_database는 데이터베이스 전체의 blks_hit와 blks_read를 보여준다. 더 세부적으로는 pg_stat_statements를 통해 쿼리별 I/O 비용과 호출 빈도를 확인할 수 있다. 이 데이터를 조합하면 어떤 쿼리가 캐시를 많이 소비하는지 파악 가능하다.
버퍼 내부 상태 확인
pg_buffercache 확장을 통해 어떤 테이블과 인덱스 블록이 버퍼를 차지하는지 확인할 수 있다. 큰 테이블이 과도하게 버퍼를 점유하면 성능 저하로 이어진다.
-- 확장 설치
CREATE EXTENSION IF NOT EXISTS pg_buffercache;
-- 테이블별 버퍼 점유 확인
SELECT relname, count(*) AS buffers
FROM pg_class c
JOIN pg_buffercache b ON b.relfilenode = pg_relation_filenode(c.oid)
GROUP BY relname
ORDER BY buffers DESC
LIMIT 20;
실무적 접근 순서
문제 해결은 단계적으로 진행한다. 측정, 원인 분석, 설정 적용, 재검증의 순서가 권장된다.
- 1) 현재 히트율 측정과 기준치 설정
- 2) 상위 I/O를 유발하는 쿼리 식별
- 3) 인덱스와 쿼리 구조 점검
- 4) 메모리 설정 조정 후 재측정
우선순위 판단 기준
- 전반적 히트율이 낮고 reads가 많은 경우 시스템 차원의 캐시 부족 의심
- 특정 쿼리나 테이블에서만 reads가 집중되면 쿼리/인덱스 튜닝 우선
설정 권장사항
shared_buffers
shared_buffers는 PostgreSQL 프로세스가 사용하는 버퍼 크기다. 일반적으로 시스템 메모리의 25% 전후가 시작점이다. 단, OS 페이지 캐시와의 관계를 고려해 과도하게 높이지 않는 편이 안전하다.
effective_cache_size
effective_cache_size는 planner에게 사용 가능한 캐시 크기를 알려준다. 시스템 메모리와 OS 캐시를 포함한 값을 추정해서 설정하면 실질적 성능 향상으로 이어진다. 예를 들면 물리 메모리 64GB 환경에서는 40GB~48GB 범위가 합리적일 수 있다.
# postgresql.conf 예시
# shared_buffers = 16GB
# effective_cache_size = 48GB
-- 설정 반영 예시
SELECT pg_reload_conf();
work_mem, maintenance_work_mem
복잡한 정렬이나 해시 조인 시 임시 파일을 줄이려면 work_mem을 적절히 늘린다. 다만 동시 세션 수를 고려해 과도하게 크게 잡지 않는다.
쿼리와 인덱스 최적화
쿼리 플랜에서 시퀀셜 스캔이 빈번하면 인덱스 추가나 통계 업데이트가 필요하다. ANALYZE와 VACUUM을 정기적으로 수행해 통계 정확도를 유지한다. 또한 불필요한 넓은 테이블 스캔을 피하기 위해 필요한 컬럼만 조회하는 습관이 도움이 된다.
모니터링과 알림 전략
정기 모니터링은 regressions를 빠르게 감지한다. 다음 항목들을 지표로 활용한다.
- 전체 히트율(주기적 측정)
- 상위 I/O 소비 쿼리 목록
- 버퍼 점유 상위 객체
- 임시 파일 생성량과 디스크 I/O 대기 시간
Prometheus, Grafana 같은 도구와 PostgreSQL exporter를 연계하면 시계열 관찰과 알림 설정이 쉬워진다. 알림 임계치는 운영 특성에 따라 달라진다.
요약과 우선 적용 항목
요약하면 postgres cache hit 개선은 측정에서 시작한다. pg_stat_database와 pg_stat_statements로 지표를 수집하고, pg_buffercache로 버퍼 점유를 확인한다. 쿼리/인덱스 튜닝을 우선 적용하고, 필요 시 shared_buffers와 effective_cache_size를 조정한다. 변경 후에는 반드시 재측정으로 효과를 검증한다. 마지막으로 모니터링을 통해 장기적인 회귀를 방지하는 체계를 갖추는 것이 핵심이다.