Autovacuum 튜닝 기본

토마스 본드라
2024년 7월 15일

이번 포스트에서는 Autovacuum 튜닝 방법에 대해 설명하며, 이를 통해 성능 문제의 위험을 최소화하는 방법을 알려드리겠습니다.

이 글에서는 먼저 왜 Autovacuum이 필요한지에 대해 간략히 설명합니다. 예를 들어, 죽은 행(dead rows)이나 bloat(공간 비효율성) 문제와 이를 Autovacuum이 어떻게 처리하는지에 대해 다룰 것입니다. 그런 다음, 이 글의 핵심 주제인 튜닝 방법으로 넘어갑니다. 모든 관련 설정 옵션과 기본적인 튜닝 규칙들을 하나씩 살펴볼 예정입니다.

참고: 이 글은 제가 2016년에 처음 작성했던 블로그 포스트를 새롭게 갱신한 버전으로, PostgreSQL 설정의 여러 변경 사항을 반영했습니다. 다만 전반적인 튜닝 접근 방식은 크게 변하지 않았습니다.

죽은 행(Dead Rows)이란 무엇인가?

Autovacuum 튜닝에 대해 이야기하기 전에 먼저 **죽은 행(Dead Rows)**이 무엇인지, 그리고 Autovacuum이 이러한 정리를 수행해야 하는 이유를 이해해야 합니다.

참고: 일부 자료에서는 “죽은 튜플(Dead Tuples)”이라는 용어를 사용하기도 합니다. 이는 본질적으로 같은 것을 다른 이름으로 부르는 것뿐입니다. “튜플(Tuple)”은 관계형 데이터베이스의 기반이 되는 관계 대수(relational algebra)에서 나온 용어로 더 추상적입니다. 반면 “행(Row)”은 구현 관점에서 더 직관적인 표현입니다. 그러나 실제로는 두 용어의 차이를 크게 구분하지 않고 서로 혼용하여 사용합니다. 이 글에서는 “행(Row)”이라는 용어를 사용하겠습니다.

Postgres에서 DELETE를 실행하면 행이 데이터 파일에서 즉시 삭제되지 않습니다. 대신, 해당 행의 헤더에 xmax 필드를 설정해 삭제되었음을 표시하는 방식으로 처리됩니다. UPDATE의 경우에도 유사한 방식으로 작동합니다. Postgres에서는 UPDATEDELETE + INSERT의 조합과 거의 동일하게 작동하기 때문입니다.

이 방식은 Postgres의 **MVCC(Multi-Version Concurrency Control, 다중 버전 동시성 제어)**의 기본 아이디어 중 하나로, 프로세스가 언제 스냅샷을 얻었는지에 따라 서로 다른 행의 하위 집합을 볼 수 있게 합니다. 예를 들어, DELETE가 실행되기 전에 시작된 SELECT는 기존 행을 볼 수 있고, DELETE가 커밋된 이후에 시작된 SELECT는 새로운 버전을 보게 됩니다(기본 READ COMMITTED 격리 수준에서).

다른 MVCC 구현은 다양한 접근 방식을 사용하지만, Postgres는 행의 복사본을 생성합니다. 이 방식의 단점은 삭제된 행이 그대로 남아 있게 된다는 것입니다. 이는 해당 버전을 볼 수 있는 모든 트랜잭션이 끝난 이후에도 마찬가지입니다.

결국, “삭제됨”으로 표시된 행이 데이터 파일에 여전히 공간을 차지하게 됩니다. 예를 들어, 어떤 행을 100번 업데이트했다면 데이터 파일에는 해당 행의 101개의 복사본이 남게 됩니다. 이러한 **죽은 행(Dead Rows)**은 정리되지 않으면 이후 트랜잭션에서 더 이상 볼 수 없더라도 데이터 파일에 영구적으로 남아 디스크 공간을 낭비하게 됩니다. DELETEUPDATE가 빈번한 테이블에서는 죽은 행이 디스크 공간의 대부분을 차지할 수 있습니다.

게다가, 이러한 죽은 행은 여전히 인덱스에서 참조되므로 인덱스에서도 불필요하게 디스크 공간을 낭비하게 됩니다.

이것이 PostgreSQL에서 흔히 말하는 Bloat입니다. 테이블과 인덱스가 최소로 필요한 공간보다 더 많은 공간을 차지하는 상태를 말합니다. 자연히, 쿼리가 처리해야 할 데이터가 많아질수록(비록 그중 99%가 “보이지 않음”으로 즉시 버려지더라도) 쿼리 성능에 영향을 미치게 됩니다.

VACUUM과 Autovacuum

죽은 행이 차지한 공간을 회수하는 가장 간단한 방법은 VACUUM 명령어를 수동으로 실행하는 것입니다. 이 유지 관리 명령은 테이블을 스캔하여 죽은 행을 테이블과 인덱스에서 제거합니다. 다만, 이 작업이 디스크 공간을 운영 체제(OS)나 파일 시스템에 반환하지는 않습니다. 대신 새로운 행이 저장될 수 있도록 해당 공간을 확보합니다.

예를 들어, 테이블 크기가 10GB인데 그중 9GB가 죽은 행으로 채워져 있다고 가정해 봅시다. VACUUM 명령이 완료되더라도 테이블 크기는 여전히 10GB로 유지됩니다. 하지만 이후 9GB의 새로운 행은 테이블을 확장하지 않고 데이터 파일에서 확보된 공간을 활용하게 됩니다. 물론 이 예는 극단적인 경우이며, 테이블에 9GB의 죽은 행이 쌓이는 것을 방치해서는 안 됩니다. 이 문제에 대해서는 곧 다루겠습니다.

참고: VACUUM FULL 명령은 공간을 회수하여 OS에 반환할 수 있지만, 몇 가지 단점이 있습니다. 이 명령은 테이블에 대해 **배타적 잠금(Exclusive Lock)**을 획득하므로, 모든 작업(읽기 전용 쿼리를 포함한)이 차단됩니다. 또한 테이블의 새 복사본을 생성하므로 디스크 공간 사용량이 두 배로 늘어날 수 있습니다. 따라서 이미 디스크 공간이 부족한 경우에는 특히 비현실적입니다.

VACUUM의 한계

수동으로 VACUUM을 실행하는 문제는, 필요할 때 자동으로 실행되지 않고 사용자가 직접 실행 시점을 결정해야 한다는 점입니다. 예를 들어, 모든 테이블에서 5분마다 VACUUM을 실행한다고 해도 대부분의 실행에서는 아무것도 정리되지 않을 가능성이 높습니다. 단순히 테이블을 확인하고 일부 데이터를 읽어들이지만, 정리할 항목이 없다는 것을 확인하는 데 그칩니다. 이렇게 되면 CPU와 I/O 리소스가 낭비됩니다.

반대로, 하루에 한 번 밤에 VACUUM을 실행한다고 가정해보면, 그 사이에 테이블에 죽은 행이 많이 쌓여 성능에 영향을 줄 수 있습니다.

즉, VACUUM 실행 주기를 적절히 조정하기는 매우 어렵습니다. 특히, 데이터베이스의 워크로드가 시간(사용자 활동 변화)이나 주기(애플리케이션 변경)에 따라 달라질 경우 더욱 그렇습니다. 한 가지 예외는 야간 배치 로드와 같은 명확한 데이터 적재 일정이 있는 시스템(예: 분석 데이터베이스)입니다.

Autovacuum: 자동 정리 프로세스

이 문제를 해결하기 위해 PostgreSQL은 Autovacuum이라는 백그라운드 프로세스를 제공합니다. 이 프로세스는 적시에 정리를 트리거하여 죽은 행으로 인한 공간 낭비를 제어할 수 있도록 설계되었습니다.

Autovacuum은 필요할 때만 실행되며, 지나치게 자주 실행되지 않도록 조정됩니다. 데이터베이스는 시간이 지남에 따라 생성된 죽은 행의 개수를 추적합니다(각 트랜잭션은 업데이트되거나 삭제된 행의 개수를 보고함). 일정 수의 죽은 행이 누적되면 Autovacuum이 정리를 트리거합니다. 덕분에 바쁜 기간 동안에는 정리가 더 자주 실행됩니다.

자동 분석 (Autoanalyze)

Autovacuum 프로세스의 책임은 죽은 행 정리에만 그치지 않습니다. 쿼리 계획에 사용되는 데이터 분포 통계 수집도 담당합니다. 이를 수동으로 수행하려면 ANALYZE 명령어를 사용할 수 있지만, 이는 VACUUM과 유사한 문제를 겪습니다. 즉, 자주 실행하기도 어렵고, 너무 자주 실행하면 리소스 낭비가 발생할 수 있습니다. 해결책 역시 유사합니다. 데이터베이스는 수정된 행의 수를 추적하여 특정 임계값을 초과하면 ANALYZE를 자동으로 실행합니다.

참고: ANALYZE의 부정적인 영향은 VACUUM보다 더 심각할 수 있습니다. VACUUM은 죽은 행의 수에 비례하는 비용을 가지므로, 죽은 행이 적을 때는 실행 비용이 낮습니다. 그러나 ANALYZE는 매번 통계를 다시 작성해야 합니다(무작위 샘플 수집 포함), 이 과정에서 상당한 I/O 비용이 발생할 수 있습니다. 한편, 테이블에 bloat가 있으면 약간의 추가 I/O로 인해 쿼리가 느려질 수 있습니다. 그러나 오래된 통계를 사용하면 비효율적인 쿼리 계획을 선택할 위험이 커지고, 이는 시간, CPU, I/O 자원을 많이 소비하게 됩니다. 차이는 기하급수적으로 커질 수 있습니다.

이 블로그 게시물의 나머지 부분에서는 Autovacuum의 이 작업에 대해서는 다루지 않겠습니다. 설정 방식은 정리 작업과 매우 유사하며, 동일한 논리를 따릅니다.

모니터링

튜닝을 시작하기 전에 먼저 관련 데이터를 수집할 수 있어야 합니다. 그렇지 않으면 튜닝이 필요한지, 또는 변경 사항의 영향을 평가할 수 없습니다. 즉, 데이터베이스에서 중요한 메트릭을 정기적으로 수집할 기본 모니터링 체계를 갖춰야 합니다.

모니터링 플러그인을 사용하는 경우(반드시 사용하는 것이 좋으며, 무료 및 상용 옵션이 많습니다), 이미 이 데이터를 보유하고 있을 가능성이 높습니다. 하지만 이 게시물에서는 데이터베이스에서 제공하는 통계를 사용하여 튜닝을 설명하겠습니다.

정리를 위해 적어도 다음 값을 확인해야 합니다:

  • pg_stat_all_tables.n_dead_tup: 각 테이블(사용자 테이블 및 시스템 카탈로그 포함)의 죽은 행 수
  • (n_dead_tup / n_live_tup): 각 테이블에서 죽은 행과 살아 있는 행의 비율
  • (pg_class.relpages / pg_class.relrows): “행당 공간”

또한, pgstattuple 확장을 사용하면 테이블 및 인덱스의 분석을 수행하여 여유 공간, 죽은 행 등의 양을 계산할 수 있습니다.

튜닝 목표

실제 설정 매개변수를 살펴보기 전에, 고수준 튜닝 목표를 간략히 논의해 보겠습니다. 즉, 매개변수를 변경할 때 달성하고자 하는 목표는 다음과 같습니다:

  1. 죽은 행 정리: 디스크 공간 낭비를 방지하고, 인덱스 bloat를 예방하며, 쿼리를 빠르게 유지합니다.
  2. 정리 작업의 영향 최소화: 정리를 너무 자주 실행하지 않아야 하며, 그렇지 않으면 CPU, I/O, RAM 리소스를 낭비하고 성능에 심각한 영향을 미칠 수 있습니다.

즉, 적절한 균형을 찾아야 합니다. 정리를 너무 자주 실행하면 너무 드문 실행만큼이나 나쁠 수 있습니다. 이 균형은 데이터 양과 DELETE/UPDATE 작업 빈도에 크게 좌우됩니다.

대부분의 설정 옵션은 매우 보수적인 기본값을 갖습니다. 기본값은 대개 과거 하드웨어 리소스(CPU, RAM 등)를 기준으로 선택되었습니다. 또한, 기본 설정은 Raspberry Pi와 같은 소형 장치나 작은 VPS 서버에서도 작동하도록 설계되었습니다. 기본값은 가끔 조정되지만(이후 게시물에서 다룰 예정), 신중하게 소규모 변경만 이루어집니다.

소규모 시스템 또는 읽기 위주의 워크로드를 처리하는 시스템의 경우 기본 설정으로도 충분히 잘 동작하지만, 대규모 시스템에서는 튜닝이 필요합니다. 데이터베이스 크기와 쓰기 작업량이 증가하면 문제가 발생하기 시작합니다.

Autovacuum 문제와 해결 방법

Autovacuum과 관련된 일반적인 문제는 정리가 충분히 자주 발생하지 않아, 나중에 실행될 때 많은 “쓰레기”를 처리해야 하며, 이로 인해 쿼리 성능에 큰 영향을 미친다는 점입니다. 이 경우 간단한 규칙을 따르십시오:

“괴롭다면, 실행 빈도가 충분하지 않은 것입니다.”

즉, Autovacuum 설정을 조정하여 정리가 더 자주 발생하도록 하지만, 매번 처리하는 죽은 행의 양은 적게 해야 합니다.

참고: 일부 사람들은 다른 규칙을 따르기도 합니다: “괴롭면 하지 않는다.” 하지만 Autovacuum을 비활성화하지 마십시오. 정말로(정말 정말로) 자신이 무엇을 하고 있는지 알고 있고, 정기적으로 실행되는 정리 스크립트(e.g., cron)를 가지고 있지 않는 한 말입니다. 그렇지 않으면 성능이 약간 저하되는 문제를 해결하기는커녕, 심각한 성능 저하 또는 가동 중단 문제에 직면하게 될 수 있습니다.

임계값과 스케일 팩터 (Thresholds and Scale Factors)

정리(cleanup)가 실행되는 시점을 조정할 때 고려할 수 있는 첫 번째 요소는 다음 두 매개변수입니다(기본값은 다음과 같습니다):

  • autovacuum_vacuum_threshold = 50
  • autovacuum_vacuum_scale_factor = 0.2

정리는 테이블의 죽은 행 수가 아래 공식을 초과할 때 실행됩니다:

threshold + pg_class.relrows * scale_factor

이 공식은 테이블의 최대 20%가 죽은 행이 될 수 있음을 의미합니다(기본값). 이때 threshold 값(50행)은 매우 작은 테이블의 너무 빈번한 정리를 방지하기 위해 설정된 값입니다. 하지만 큰 테이블에서는 스케일 팩터가 더 중요한 역할을 합니다.

기본값의 문제점

특히 스케일 팩터(0.2)의 문제는 다음과 같습니다. 이 값은 테이블의 “낭비 가능한” 비율을 결정하며, 작은 테이블이나 중간 크기의 테이블에는 적합합니다. 예를 들어, 10GB 테이블에서는 2GB의 죽은 행을 허용하는데, 이는 적절한 수준입니다. 그러나 1TB 테이블에서는 200GB의 죽은 행을 허용하게 됩니다. 정리가 실행될 때 이 모든 데이터를 한꺼번에 처리해야 하므로 성능에 큰 영향을 미칩니다.

해결책: 더 자주 정리 실행

이 문제를 해결하려면 스케일 팩터를 줄여 정리를 더 자주 실행하도록 설정합니다. 예를 들어:

autovacuum_vacuum_scale_factor = 0.01

이렇게 하면 허용 가능한 죽은 행 비율이 테이블의 1%로 줄어듭니다. 즉, 1TB 테이블의 경우 약 10GB의 죽은 행이 누적되면 정리가 실행됩니다. 또는 스케일 팩터를 완전히 제거하고 임계값만 사용하는 방법도 있습니다:

autovacuum_vacuum_scale_factor = 0

autovacuum_vacuum_threshold = 10000

이 설정은 죽은 행이 10,000개 생성될 때마다 정리를 실행합니다.

작은 테이블에 대한 고려사항

스케일 팩터를 줄이면 작은 테이블에서 정리가 더 자주 실행될 수 있습니다. 예를 들어, 행이 1,000개인 테이블에서 스케일 팩터가 1%라면, 단 10행을 업데이트해도 정리가 실행될 수 있습니다. 이는 지나치게 빈번한 정리로 이어질 수 있습니다.

그러나 작은 테이블의 정리는 일반적으로 비용이 적게 들기 때문에 무시해도 괜찮습니다. 특히 큰 테이블에서의 개선 효과가 크다면, 작은 테이블을 더 자주 처리해도 전체적인 효과는 긍정적입니다.

그래도 이를 방지하려면 임계값을 조금 높일 수 있습니다. 다음과 같은 설정이 가능합니다:

autovacuum_vacuum_scale_factor = 0.01

autovacuum_vacuum_threshold = 1000

이 설정은 테이블이 죽은 행 1,000개와 테이블 크기의 1%를 초과하면 정리를 실행합니다. 작은 테이블에서는 1,000행이 기준이 되고, 큰 테이블에서는 1% 스케일 팩터가 더 중요해집니다.

개별 테이블에 대한 조정

postgresql.conf 파일의 매개변수는 클러스터 전체(모든 데이터베이스와 테이블)에 영향을 미칩니다. 따라서 일부 큰 테이블만 조정하려면 ALTER TABLE 명령어를 사용할 수 있습니다:

ALTER TABLE large_table SET (autovacuum_vacuum_scale_factor = 0.01);

ALTER TABLE large_table SET (autovacuum_vacuum_threshold = 10000);

하지만 이러한 방법은 정리 동작의 디버깅과 분석을 복잡하게 만들 수 있으므로, 가능한 한 postgresql.conf에서 매개변수를 조정하고, 다른 방법은 마지막 수단으로 사용하는 것이 좋습니다.

참고: 이 매개변수를 얼마나 낮게 설정해야 할까요? 왜 스케일 팩터를 0.001(즉, 1TB 테이블에서 0.1%, 1GB)로 설정하지 않을까요? 시도해 볼 수는 있지만, 저는 이렇게 낮은 값을 권장하지 않습니다.

“낭비된” 공간은 새 데이터를 위한 버퍼 역할을 하며, 시스템에 여유를 줍니다. 예를 들어, 200GB에서 10GB로 줄이는 것은 많은 공간을 절약하면서도 새 행을 위한 충분한 공간을 남겨둡니다. 그러나 10GB에서 1GB로 줄이는 것은 이득이 훨씬 적습니다.

또한, 정리가 너무 일찍 실행될 위험이 있습니다. 즉, 아직 삭제될 수 없는 행을 처리하기 위해 정리가 시도되며, 결국 정리가 다시 시도되는 상황을 초래할 수 있습니다. 이는 바람직하지 않습니다.

스로틀링 (Throttling)

Autovacuum 시스템의 중요한 기능 중 하나는 **스로틀링(Throttling)**입니다. 정리 작업은 사용자 쿼리에 최소한의 영향을 미치도록 설계된 백그라운드 유지 관리 작업이어야 합니다. 정리가 너무 많은 리소스(CPU 및 디스크 I/O)를 소비하여 일반 사용자 활동(예: 쿼리 속도 저하)에 영향을 미치지 않도록 해야 합니다. 이를 위해 정리가 일정 시간 동안 사용할 수 있는 리소스를 제한하는 메커니즘이 필요합니다.

정리 작업은 간단한 과정으로 이루어집니다. 데이터 파일에서 **페이지(8KB 단위 데이터 청크)**를 읽고 해당 페이지에 정리가 필요한지 확인합니다.

  • 죽은 행이 없는 경우: 페이지는 아무 변경 없이 버려집니다.
  • 죽은 행이 있는 경우: 페이지는 정리되고(죽은 행 제거), “더러워진(dirty)” 상태로 표시된 후 캐시를 거쳐 디스크에 기록됩니다.

PostgreSQL 14 기준으로 작업의 리소스 비용은 다음과 같이 정의됩니다(특별한 언급이 없으면 PG 14 값을 사용):

작업옵션PG 14+ 비용PG 13 이하 비용
공유 버퍼에서 페이지 읽기vacuum_cost_page_hit11
OS/디스크에서 페이지 읽기vacuum_cost_page_miss210
페이지 정리 후 쓰기vacuum_cost_page_dirty2020

이 설명에 따르면, 페이지가 공유 버퍼에서 발견되면 1 토큰의 비용이 발생합니다. 만약 페이지를 운영 체제(OS)에서 읽어야 한다면(디스크에서 읽는 경우 포함), 약간 더 비싼 작업으로 간주되어 2 토큰의 비용이 부과됩니다. 마지막으로, 정리 과정에서 페이지가 더러워져(dirtied) 디스크에 기록되어야 한다면 20 토큰의 비용이 발생합니다. 이를 통해 Autovacuum이 수행한 작업을 시간에 따라 계량 할 수 있습니다.

스로틀링 작동 방식

스로틀링은 한 번에 수행할 수 있는 작업량을 제한하여 이루어집니다. 기본값으로 작업량 한도는 200 토큰으로 설정되어 있으며, 작업이 이 한도에 도달하면 짧은 시간 동안 대기합니다. PostgreSQL 12 이전에는 대기 시간이 20ms였으나, PG 12부터는 2ms로 줄어들었습니다.

autovacuum_vacuum_cost_delay = 2ms

autovacuum_vacuum_cost_limit = 200

PG 12에서 대기 시간이 변경되면서, PostgreSQL 릴리스별로 작업량 계산이 다르게 이루어집니다.

  • 2ms 대기 시간으로 정리 작업은 초당 500회 실행할 수 있습니다.
  • 작업 한도가 200 토큰일 때, 초당 100,000 토큰의 작업량이 허용됩니다(PG 12 이전 릴리스에서는 한도가 초당 10,000 토큰).

정리 작업 속도:

작업 내용PG 14+PG 12/13PG 11
공유 버퍼 읽기800 MB/s80 MB/s80 MB/s
OS/디스크 읽기400 MB/s40 MB/s8 MB/s
페이지 쓰기(더러워진 페이지)40 MB/s4 MB/s4 MB/s

현재 하드웨어의 성능(로컬 스토리지를 가정)을 고려할 때, PostgreSQL 14 이전 버전의 기본 제한값은 다소 낮을 가능성이 있습니다. 처리량을 5~10배 증가시키기 위해 cost limit 값을 1000~2000으로 늘리거나, 비슷한 비율로 cost delay를 줄이는 것이 좋습니다.

물론 다른 매개변수(페이지 작업당 비용, 대기 시간 등)를 조정할 수도 있지만, 일반적으로 그렇게 하지 않습니다. cost limit을 조정하는 것만으로도 충분히 효과적입니다.

PostgreSQL 14에서는 기본 제한값이 크게 증가하여 더 적절한 기본값을 제공합니다.

참고: 일반 VACUUM도 동일한 스로틀링 메커니즘을 가지고 있지만, 기본적으로 비활성화되어 있습니다(vacuum_cost_delay가 0으로 설정됨). 하지만 수동으로 VACUUM을 실행해야 할 경우, 스로틀링을 활성화하면 데이터베이스의 다른 작업(예: 사용자 쿼리)에 미치는 영향을 줄일 수 있습니다.

작업자 수 (Number of Workers)

지금까지 언급하지 않은 설정 옵션 중 하나는 **autovacuum_max_workers**입니다. 이 옵션은 무엇일까요?
정리 작업은 단일 Autovacuum 프로세스에 의해 수행되지 않습니다. 대신, 데이터베이스는 **autovacuum_max_workers**로 설정된 최대 개수만큼의 작업자 프로세스를 실행하며, 이 작업자들이 실제 정리를 수행합니다(각 작업자는 한 번에 하나의 테이블만 처리). 기본 설정에서는 최대 3개의 작업자를 허용합니다.

이는 유용한 기능입니다. 예를 들어, 작은 테이블의 정리를 중단하지 않고, 큰 테이블 하나가 정리되는 데 시간이 오래 걸리더라도 동시에 정리를 수행할 수 있습니다(스로틀링 때문에 큰 테이블 정리에 시간이 걸릴 수 있음).

작업자 수 증가에 대한 오해

문제는 사용자가 작업자 수를 늘리면 정리 작업량도 늘어난다고 생각한다는 점입니다. 예를 들어, 작업자를 기본값인 3명에서 6명으로 늘리면 정리 작업량이 두 배가 될 것이라고 가정할 수 있습니다. 하지만 실제로는 그렇지 않습니다.

이유는 **비용 한도(cost limit)**가 앞서 설명했듯이 **전역 값(global)**으로, 실행 중인 모든 Autovacuum 작업자들이 공유하기 때문입니다. 각 작업자는 전역 비용 한도의 일부(대략 1/autovacuum_max_workers)만 사용할 수 있습니다. 따라서 작업자 수를 늘리면 각 작업자의 속도가 느려질 뿐, 정리 작업의 처리량이 늘어나지 않습니다.

이를 고속도로에 비유할 수 있습니다. 자동차 수를 두 배로 늘리지만 속도를 절반으로 줄이면, 시간당 목적지에 도달하는 사람 수는 거의 동일하게 유지됩니다.

따라서 데이터베이스의 정리 작업이 사용자 활동을 따라가지 못하는 경우, 작업자 수를 늘리는 것만으로는 해결되지 않습니다. 대신, 다른 매개변수(예: autovacuum_vacuum_cost_limit, autovacuum_vacuum_cost_delay)를 먼저 조정해야 합니다.

테이블별 스로틀링 (Per-table Throttling)

앞서 **비용 한도(cost limit)**가 전역(global)으로 설정되어 모든 Autovacuum 작업자가 공유한다고 언급했지만, 이는 완전히 정확한 설명은 아닙니다. **스케일 팩터(scale factor)**와 **임계값(threshold)**처럼, 비용 한도와 대기 시간도 테이블별로 정의할 수 있습니다:

ALTER TABLE t SET (autovacuum_vacuum_cost_limit = 1000);

ALTER TABLE t SET (autovacuum_vacuum_cost_delay = 10);

이렇게 사용자 정의 한도가 설정된 테이블을 처리하는 작업자는 전역 비용 한도에 포함되지 않고, 대신 독립적으로 스로틀링됩니다(즉, 이 한도는 해당 작업자에만 적용됨).

실무에서의 사용과 권장사항

실제로 이 기능은 거의 사용되지 않으며, 사용하지 않는 것이 좋습니다.
이 기능은 정리 작업의 동작을 예측하거나 분석하기 어렵게 만듭니다. 일부 작업자는 전역적으로 스로틀링되고, 일부는 독립적으로 스로틀링되는 상황은 매우 복잡해질 수 있습니다.

대부분의 경우, 백그라운드 정리를 위한 단일 전역 한도를 사용하는 것이 바람직합니다.

마치며


다섯 가지 기본 규칙으로 요약하자면 다음과 같습니다:

  1. Autovacuum을 비활성화하지 마세요. 정말로 자신이 무엇을 하고 있는지 확신하지 않는 한 절대 비활성화하지 마세요. 진심입니다.
  2. 활발히 사용되는 데이터베이스, 특히 UPDATEDELETE가 많은 대규모 데이터베이스의 경우, 스케일 팩터를 줄여 정리가 더 자주 이루어지도록 설정하세요.
  3. 적절한 하드웨어(빠른 스토리지, 다중 코어)가 있는 경우, 스로틀링 매개변수를 증가시켜 정리가 데이터베이스 작업을 따라갈 수 있도록 해야 합니다. 특히 PostgreSQL 14 이전 버전에서 더 중요합니다.
  4. autovacuum_max_workers만 증가시키는 것은 대부분의 경우 도움이 되지 않습니다. 이는 정리 작업의 처리량을 늘리지 않습니다. 작업자 수는 늘어나지만 각 작업자는 더 느리게 작동합니다.
  5. ALTER TABLE을 사용해 테이블별로 매개변수를 설정할 수 있지만, 정말 필요한지 신중히 고민하세요. 이 설정은 시스템을 복잡하게 만들고 문제를 파악하기 어렵게 합니다.

본문 : Autovacuum Tuning Basics

EDB 영업 기술 문의: 02-501-5113

이메일: salesinquiry@enterprisedb.com

홈페이지 문의: https://www.enterprisedb.com/contact_kr