PostgreSQL: Autovacuum 최적화
※ PostgreSQL: autovacuum optimization.
안녕하세요. 듀스트림입니다.
PostgreSQL을 사용하시는 분들은 VACUUM 때문에 조금씩은 머리가 아프실 거에요.
이번 포스팅은 유지관리에서 가장 신경써야할 것 중 하나인 autovacuum에 관한 내용입니다.
19.10. Automatic Vacuuming
19.10. Automatic Vacuuming # These settings control the behavior of the autovacuum feature. Refer to Section 24.1.6 for more information. Note that …
www.postgresql.org
오토배큠에 대한 PostgreSQL 공식 문서입니다.
네.. 저도 알아요. 여러분이 이런 걸 바라는 게 아니라는걸...
그럼 실제 운영환경에서 튜닝하는 주요 파라미터와 방법만 뽑아서 알아보겠습니다.
파라미터에 대한 자세한 설명은 공식 문서 참고 부탁드립니다.
1. 환경 및 워크로드 분석
• 데이터 변경 패턴 파악
→ 각 테이블의 INSERT, UPDATE, DELETE 빈도 및 변경량 분석.
→ 테이블별 변경률을 기반으로 autovacuum 트리거 기준(vacuum_scale_factor, vacuum_threshold)을 설정.
• Hot-standby를 사용하는 HA 환경 고려
→ standby 서버와의 충돌 최소화를 위해 primary의 VACUUM 부하 및 지연 시간 조절.
→ hot_standby_feedback과 연계하여 trade-off 분석.
2. 주요 autovacuum 파라미터
2.1. 기본 파라미터
- autovacuum_naptime
- 목적: autovacuum 프로세스 간의 간격 조정.
- 예시:
# postgresql.conf
autovacuum_naptime = 200s
- autovacuum_vacuum_scale_factor, autovacuum_vacuum_threshold
- 목적: dead tuple의 비율이 기준에 도달할 때만 VACUUM 실행.
- 예시:
# postgresql.conf
autovacuum_vacuum_threshold = 100000 # 기본값 50
autovacuum_vacuum_scale_factor = 0.3 # 기본값 0.2
-- 테이블 별 설정
ALTER TABLE table_name
SET (autovacuum_vacuum_scale_factor = 0.2, autovacuum_vacuum_threshold = 100);
2.2. VACUUM 작업 부하 제어 파라미터
- autovacuum_vacuum_cost_delay
- 목적: VACUUM 중 I/O 부하 감소.
→ VACUUM 작업이 일정 비용(autovacuum_vacuum_cost_limit에 도달) 후 설정 시간만큼 작업을 멈춤.
→ 이 휴식 시간 동안 다른 프로세스들이 I/O 자원을 사용할 수 있게 되어, 전체 시스템의 I/O 부하가 분산됨. - 예시:
- 목적: VACUUM 중 I/O 부하 감소.
# postgresql.conf에서 설정
autovacuum_vacuum_cost_delay = 50ms
- autovacuum_vacuum_cost_limit
- 목적: 한 사이클에 수행할 비용 상한 설정.
→ 기본값인 -1로 설정하면 vacuum_cost_limit 파라미터 값이 사용됨. - 각 작업에 대한 기본 비용:
→ vacuum_cost_page_hit (기본값: 1): Shared buffer에서 페이지를 읽을 때의 비용 (메모리 I/O)
→ vacuum_cost_page_miss (기본값: 2): 디스크에서 페이지를 읽을 때의 비용 (디스크 I/O)
→ vacuum_cost_page_dirty (기본값: 20): 변경된 페이지(dirty block)를 디스크에 기록(flush)할 때의 비용 - 예시:
- 목적: 한 사이클에 수행할 비용 상한 설정.
# postgresql.conf
autovacuum_vacuum_cost_limit = 2000 # 기본값 -1(vacuum_cost_limit 기본값 200)
2.3. 트랜잭션 ID 및 인덱스 관리
- autovacuum_freeze_max_age & vacuum_freeze_min_age
- 목적: 트랜잭션 ID wraparound 예방 및 인덱스 bloat 관리.
→ 업데이트가 잦은 환경에서는 freezing 작업을 빠르게 불러 wraparound를 방지하기 위해 기본값보다 수치를 낮추기도 함.
→ 너무 작은 값으로 설정하면 freezing 자주 발생, xmin이 FrozenXID로 변경되면서 테이블 및 인덱스가 자주 업데이트됨. (freezing 작업은 update와 같은 형태로 동작)
→ freezing이 일어나면 인덱스 엔트리도 해당 레코드의 새로운 위치에 맞게 수정되지만, 기존 인덱스 항목은 제거되지 않기 때문에 시간이 지나면서 불필요한 인덱스 엔트리(bloat)가 계속 증가. - 예시:
- 목적: 트랜잭션 ID wraparound 예방 및 인덱스 bloat 관리.
# postgresql.conf
autovacuum_freeze_max_age = 150000000 # 기본값 200000000
vacuum_freeze_min_age = 3000000 # 기본값 5000000
+ 자세한 파라미터들은 아래 포스팅 참고 부탁드립니다.
PostgreSQL: Autovacuum 파라미터
※ PostgreSQL: Autovacuum Parameters.※ Version: PostgreSQL 16. 안녕하세요. 듀스트림입니다. 오늘은 유지관리에서 중요한 Autovacuum 파라미터들을 알아보고 튜닝 포인트와 주의사항에 대해 알아보겠습니다.
dewstream.tistory.com
3. 테이블별 최적화 전략
3.1. 업데이트가 잦은 테이블
• 낮은 vacuum_scale_factor 및 vacuum_threshold 적용.
ALTER TABLE table_name
SET (autovacuum_vacuum_scale_factor = 0, autovacuum_vacuum_threshold = 1000000);
3.2. 업데이트가 거의 없는 테이블
• 튜닝 불필요.
3.3. 적재된 데이터가 얼마 없는 신생 테이블
• autovacuum_vacuum_threshold 값을 높게 설정하여 불필요한 autovacuum 방지.
ALTER TABLE table_name
SET (autovacuum_vacuum_threshold = 5000000);
3.4. 파티셔닝된 테이블
• 파티션 테이블 수가 많을 경우 autovacuum_max_workers 수를 높여 VACUUM 작업 병목 발생 방지.
# postgresql.conf
autovacuum_max_workers = 10 # 기본값 3
-- 서버 사양 및 PostgreSQL의 총 워커 프로세스 수를 고려하여 조정 필요.
• 각 파티션마다 독립적인 autovacuum 설정 적용.
• 필요에 따라 파티션 단위로 autovacuum_enabled를 조정하거나, 수동 VACUUM 계획 수립.
ALTER TABLE table_2025_01
SET (autovacuum_vacuum_scale_factor = 0.3, autovacuum_vacuum_threshold = 50000);
ALTER TABLE table_2025_02
SET (autovacuum_vacuum_scale_factor = 0.2, autovacuum_vacuum_threshold = 100000);
3.5. 특정 테이블 autovacuum 비활성화
• 장시간 실행되는 쿼리 등으로 인해 충돌 위험이 높은 경우 적용.
• 반드시 수동 VACUM 계획을 수립해야 함. (쉘을 활용한 VACUUM 배치 cron 등록 등)
ALTER TABLE table_name SET (autovacuum_enabled = false);
3.6. autovacuum에 의한 ANALYZE 비활성화 (우회적 방식)
• PostgreSQL은 autovacuum_analyze_enabled 옵션을 제공하지 않으므로, ANALYZE만 직접적으로 끄는 설정은 불가능.
• autovacuum_analyze_threshold와 autovacuum_analyze_scale_factor 값을 비정상적으로 높게 설정하여 ANALYZE가 사실상 트리거되지 않도록 구성 가능.
• 이 방식은 실행 계획 품질 저하의 위험이 있으므로 정기적인 수동 ANALYZE 수행이 필요.
ALTER TABLE table_name SET (autovacuum_analyze_threshold = 5000000000, autovacuum_analyze_scale_factor = 50.0);
3.7. 매일 정량적 INSERT가 일어나는 테이블
• 매일 일정량의 데이터가 INSERT되는 테이블은 변경 비율이 아닌 정량 기준으로 VACUUM 트리거를 설정하는 것이 유리함.
• autovacuum_vacuum_insert_scale_factor = 0으로 설정하고, 튜플 수 기준으로만 작동하도록 조정.
• INSERT량이 명확하다면 적절한 autovacuum_vacuum_insert_threshold 값으로 컨트롤 가능.
ALTER TABLE table_name SET (autovacuum_vacuum_insert_scale_factor = 0, autovacuum_vacuum_insert_threshold = 2000000);
3.8. 오래된 트랜잭션으로 인한 autovacuum 실패 방지
• autovacuum 시 idle in transaction이 해당 테이블을 점유하고 있으면 autovacuum이 정상적으로 수행되지 않음.
• idle_in_transaction_session_timeout을 AP 수준에 맞게 조정. (이 설정은 트랜잭션 누수 방지와 락 점유 방지를 위해서라도 대부분의 경우 설정 권장)
# postgresql.conf
idle_in_transaction_session_timeout = 15min # 기본값 -1(무제한)
ALTER SYSTEM SET idle_in_transaction_session_timeout = '15min';
-- 데이터베이스 단위
ALTER DATABASE db_name SET idle_in_transaction_session_timeout = '15min';
-- 사용자 단위
ALTER ROLE user_name SET idle_in_transaction_session_timeout = '15min';
-- 설정 후 pg_ctl reload/SELECT pg_reload_conf(); 필요
4. Hot-standby를 사용하는 HA 환경에서의 고려사항
• hot_standby_feedback 활성화
→ standby에서 수행하는 장시간 쿼리 보호를 위해 사용할 수 있지만, primary의 VACUUM 지연에 따른 bloat, 복제 지연 등 모니터링 필수.
• VACUUM 부하 조절
→ primary에서의 autovacuum 부하로 인한 standby 충돌 최소화를 위해 cost delay/limit 값 조정.
→ standby 쿼리 모니터링과 replication lag 지표(pg_stat_replication, pg_stat_database_conflicts) 모니터링 필수.
5. 모니터링 전략
5.1. 주기적인 테이블 bloat 상태, autovacuum 동작 유무 모니터링
SELECT
relname AS table_name,
pg_total_relation_size(relid) / (1024*1024) ||' MB' AS table_size,
n_live_tup AS live_tuples,
n_dead_tup AS dead_tuples,
CASE
WHEN n_live_tup = 0 THEN 0.00
ELSE round(n_dead_tup::numeric / n_live_tup::numeric * 100.0, 2)
END AS dead_tuple_ratio,
last_autovacuum AS last_autovacuum_time
FROM pg_stat_user_tables
ORDER BY dead_tuple_ratio, table_size DESC;
5.2. PostgreSQL 로그 파라미터 설정
• autovacuum 작업을 로그에 기록하여 정상 수행, 충돌 여부 등 이상 징후를 파악.
• 값을 0으로 하면 모든 autovacuum 작업을 로그에 기록.
# postgresql.conf
log_autovacuum_min_duration = 0 # 기본값 10min
주기적인 모니터링과 로그 분석을 통해, 전역 설정과 테이블별 설정을 조합하여 VACUUM 부하와 테이블 bloat, 트랜잭션 ID wraparound 문제를 균형 있게 관리하는 게 중요합니다.
Hot-standby를 사용하는 HA 환경에서는 standby와의 충돌을 최소화하기 위해 추가 설정(hot_standby_feedback, cost_delay 등 + max_standby_streaming_delay)과 모니터링이 필수입니다.
오늘은 여기까지~