PostgreSQL의 적극적인 Autovacuum


42

PostgreSQL이 적극적으로 데이터베이스를 자동 진공 청소기로 청소하려고합니다. 현재 다음과 같이 자동 진공을 구성했습니다.

  • autovacuum_vacuum_cost_delay = 0 # 비용 기반 진공 끄기
  • autovacuum_vacuum_cost_limit = 10000 # 최대 값
  • autovacuum_vacuum_threshold = 50 # 기본값
  • autovacuum_vacuum_scale_factor = 0.2 # 기본 값

데이터베이스가로드되지 않은 경우에만 자동 진공이 시작되므로 라이브 튜플보다 죽은 튜플이 훨씬 많은 상황에 처하게됩니다. 예제는 첨부 된 스크린 샷을 참조하십시오. 테이블 중 하나에는 23 개의 라이브 튜플이 있지만 진공을 기다리는 16845 개의 죽은 튜플이 있습니다. 미쳤다!

죽은 튜플을 많이

테스트 실행이 완료되고 데이터베이스 서버가 유휴 상태 일 때 자동 진공이 시작됩니다. 데이터베이스가 종료되었으므로 죽은 튜플의 수가 20 % 라이브 튜플 + 50을 초과 할 때마다 자동 진공을 시작하기를 원하지 않습니다. 구성되었습니다. 서버가 유휴 상태 일 때 자동 진공 처리는 나에게 쓸모가 없습니다. 프로덕션 서버는 지속적으로 1000 초 / 초의 업데이트를받을 것으로 예상되므로 서버가로드 상태 일 때도 자동 진공을 실행해야합니다.

내가 놓친 것이 있습니까? 서버가 과부하 상태 일 때 자동 진공을 강제로 실행하려면 어떻게합니까?

최신 정보

이것이 잠금 문제 일 수 있습니까? 해당 테이블은 삽입 후 트리거를 통해 채워지는 요약 테이블입니다. 이 테이블은 SHARE ROW EXCLUSIVE 모드에서 잠기므로 동일한 행에 동시 쓰기를 방지 할 수 있습니다.

답변:


40

Eelke는 잠금 장치가 자동 진공 장치를 차단하고 있다는 것이 거의 확실합니다. Autovacuum은 고의로 사용자 활동에 방해가되지 않도록 설계되었습니다. 해당 테이블이 잠겨 있으면 자동 진공 청소기로 진공 청소기로 청소할 수 없습니다.

그러나 후손을 위해, 나는 당신이 준 설정이 그렇게하지 않기 때문에 과도 공격적 autovacuum에 대한 설정의 예를 제시하고 싶었습니다. 그러나 autovacuum을보다 공격적으로 만드는 것은 문제를 해결하지 못할 것입니다. 또한 기본 자동 진공 설정은 최적의 설정 조합을 찾는 DBT2를 사용하여 200 회 이상의 테스트 실행을 기반으로하므로 달리 생각할만한 확실한 이유가 없거나 데이터베이스가 크게 외부에 있지 않는 한 기본값은 양호한 것으로 가정해야합니다. OLTP 데이터베이스의 주류 (예 : 초당 10K 업데이트를받는 작은 데이터베이스 또는 3TB 데이터웨어 하우스).

먼저 로깅을 켜서 autovacuum이 생각한대로 작동하는지 확인할 수 있습니다.

log_autovacuum_min_duration = 0

그런 다음 더 많은 autovac 근로자를 만들고 더 자주 테이블을 확인하도록하겠습니다.

autovacuum_max_workers = 6
autovacuum_naptime = 15s

자동 진공 및 자동 분석에 대한 임계 값을 낮추어 더 빨리 트리거하겠습니다.

autovacuum_vacuum_threshold = 25
autovacuum_vacuum_scale_factor = 0.1

autovacuum_analyze_threshold = 10
autovacuum_analyze_scale_factor = 0.05 

그런 다음 autovacuum의 중단 가능성을 줄이면서 더 빨리 완료하지만 동시 사용자 활동에 더 큰 영향을 미칩니다.

autovacuum_vacuum_cost_delay = 10ms
autovacuum_vacuum_cost_limit = 1000

일반적으로 공격적인 autovacuum에 대한 전체 프로그램이 있습니다.이 프로그램은 매우 빠른 속도로 업데이트하는 소규모 데이터베이스에 적합하지만 동시 사용자 활동에 너무 큰 영향을 줄 수 있습니다.

또한 autovacuum 매개 변수는 테이블 당 조정할 수 있으므로 autovacuum의 동작을 조정해야 할 경우 거의 항상 더 나은 대답입니다.

그러나 다시 한 번, 실제 문제를 해결하지는 못할 것입니다.


36

autovacuum에 적합한 테이블을 확인하기 위해 다음 쿼리를 사용할 수 있습니다 ( http://www.postgresql.org/docs/current/static/routine-vacuuming.html 기반 ). 그러나 쿼리는 테이블 특정 설정을 찾지 않습니다.

 SELECT psut.relname,
     to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI') as last_vacuum,
     to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI') as last_autovacuum,
     to_char(pg_class.reltuples, '9G999G999G999') AS n_tup,
     to_char(psut.n_dead_tup, '9G999G999G999') AS dead_tup,
     to_char(CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
         + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
            * pg_class.reltuples), '9G999G999G999') AS av_threshold,
     CASE
         WHEN CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
             + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
                * pg_class.reltuples) < psut.n_dead_tup
         THEN '*'
         ELSE ''
     END AS expect_av
 FROM pg_stat_user_tables psut
     JOIN pg_class on psut.relid = pg_class.oid
 ORDER BY 1;

11

예, 잠금 문제입니다. 이 페이지 에 따르면 (전체가 아님) VACUUM은 사용중인 잠금 수준에 의해 차단되는 SHARE UPDATE EXCLUSIVE 액세스 권한이 필요합니다.

이 자물쇠가 필요한가요? PostgreSQL은 ACID를 준수하므로 직렬화 위반이 발생할 경우 PostgreSQL이 트랜잭션 중 하나를 중단하므로 동시 쓰기는 문제가되지 않습니다.

또한 SELECT FOR UPDATE 를 사용 하여 전체 테이블 대신 행을 잠그면 행을 잠글 수 있습니다.

잠금없는 다른 대안은 직렬화 가능한 트랜잭션 격리 레벨을 사용하는 것 입니다. 그러나 이것은 다른 트랜잭션의 성능에 영향을 줄 수 있으며 더 많은 직렬화 실패에 대비해야합니다.


이는 SHARE ROW EXCLUSIVE MODE를 사용하여 요약 된 요약 테이블의 잠금으로 인한 것입니다. 잠금이없는 동시 쓰기는 성공할 수 있지만 대부분 잘못된 값으로 끝날 것입니다. X 유형의 N 행 수를 유지한다고 가정합니다. X 유형의 2 행을 동시에 삽입하지 않으면 N + 2 대신 요약 테이블에서 N + 1로 끝납니다. 내 데이터베이스에서 요약 테이블을 수동으로 진공 청소기로 청소하는 크론 작업을하는 것입니다. 그것은 잘 작동하고 권장되는 접근 방법 인 것처럼 보이지만 나에게는 해킹처럼 너무 많이 느낍니다.
CadentOrange

6

autovacuum 프로세스 수를 늘리고 낮잠 시간을 줄이면 도움이 될 것입니다. 백업 정보를 저장하고 결과적으로 많은 삽입 작업을 수행하는 서버에서 사용하는 PostgreSQL 9.1의 구성이 있습니다.

http://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html

autovacuum_max_workers = 6              # max number of autovacuum subprocesses
autovacuum_naptime = 10         # time between autovacuum runs
autovacuum_vacuum_cost_delay = 20ms     # default vacuum cost delay for

cost_delay진공 청소기를 더욱 공격적으로 만들기 위해를 낮추려고 노력할 것 입니다.

pgbench를 사용하여 자동 진공 청소기를 테스트 할 수도 있습니다.

http://wiki.postgresql.org/wiki/Pgbenchtesting

고 경쟁 예 :

bench_replication 데이터베이스 생성

pgbench -i -p 5433 bench_replication

pgbench 실행

pgbench -U postgres -p 5432 -c 64 -j 4 -T 600 bench_replication

자동 진공 상태 확인

psql
>\connect bench_replicaiton
bench_replication=# select schemaname, relname, last_autovacuum from pg_stat_user_tables;
 schemaname |     relname      |        last_autovacuum        
------------+------------------+-------------------------------
 public     | pgbench_branches | 2012-07-18 18:15:34.494932+02
 public     | pgbench_history  | 
 public     | pgbench_tellers  | 2012-07-18 18:14:06.526437+02
 public     | pgbench_accounts | 

6

기존 "autovacuum에 대한 자격"스크립트는 매우 유용하지만 (올바르게 언급 된대로) 테이블 특정 옵션이 누락되었습니다. 다음은 이러한 옵션을 고려한 수정 된 버전입니다.

WITH rel_set AS
(
    SELECT
        oid,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)::BIGINT
        END AS rel_av_vac_threshold,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)::NUMERIC
        END AS rel_av_vac_scale_factor
    FROM pg_class
) 
SELECT
    PSUT.relname,
    to_char(PSUT.last_vacuum, 'YYYY-MM-DD HH24:MI')     AS last_vacuum,
    to_char(PSUT.last_autovacuum, 'YYYY-MM-DD HH24:MI') AS last_autovacuum,
    to_char(C.reltuples, '9G999G999G999')               AS n_tup,
    to_char(PSUT.n_dead_tup, '9G999G999G999')           AS dead_tup,
    to_char(coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples, '9G999G999G999') AS av_threshold,
    CASE
        WHEN (coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples) < PSUT.n_dead_tup
        THEN '*'
    ELSE ''
    END AS expect_av
FROM
    pg_stat_user_tables PSUT
    JOIN pg_class C
        ON PSUT.relid = C.oid
    JOIN rel_set RS
        ON PSUT.relid = RS.oid
ORDER BY C.reltuples DESC;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.