PostgreSQLでの積極的な自動バキューム


42

私はPostgreSQLに積極的にデータベースを自動バキュームさせようとしています。現在、自動バキュームを次のように構成しています。

  • autovacuum_vacuum_cost_delay = 0#コストベースのバキュームをオフにする
  • autovacuum_vacuum_cost_limit = 10000#最大値
  • autovacuum_vacuum_threshold = 50#デフォルト値
  • autovacuum_vacuum_scale_factor = 0.2#デフォルト値

自動バキュームは、データベースに負荷がかかっていないときにのみ作動することに気付きました。そのため、ライブタプルよりもはるかに多くのデッドタプルが存在する状況に陥ります。例については、添付のスクリーンショットを参照してください。テーブルの1つには23個のライブタプルがありますが、16845個のデッドタプルがバキュームを待っています。それは非常識です!

死んだタプルがたくさん

テスト実行が終了し、データベースサーバーがアイドル状態になると、自動バキュームが開始されます。これは、データベースが既に稼働しているため、デッドタプルの数が20%のライブタプル+ 50を超えるたびに自動バキュームを開始したいので、これは望ましくありません設定済み。サーバーがアイドル状態のときの自動バキュームは、私にとって役に立たない。なぜなら、実稼働サーバーは、サーバーが負荷がかかっている場合でも実行するために自動バキュームが必要な理由で、持続時間にわたって1000更新/秒に達することが予想されるためである。

不足しているものはありますか?サーバーの負荷が高いときに自動バキュームを実行するにはどうすればよいですか?

更新

これはロックの問題でしょうか?問題の表は、挿入後トリガーを介して移入されるサマリー表です。これらのテーブルはSHARE ROW EXCLUSIVEモードでロックされ、同じ行への同時書き込みを防ぎます。

回答:


40

Eelkeは、ロックがautovacuumをブロックしていることをほぼ間違いなく正しいです。Autovacuumは、ユーザーのアクティビティに意図的に道を譲るように設計されています。それらのテーブルがロックされている場合、自動バキュームはそれらをバキュームできません。

しかし、後世のために、私はあなたが与えた設定はそれを全くしないので、ハイパーアグレッシブなオートバキュームの設定セットの例を与えたいと思いました。ただし、自動バキュームをより積極的にすることで問題が解決する可能性は低いことに注意してください。また、デフォルトの自動バキューム設定は、DBT2を使用して設定の最適な組み合わせを求める200回以上のテスト実行に基づいているため、別の考えをする明確な理由がない限り、またはデータベースが大幅に外部にある場合を除き、デフォルトは適切であると想定する必要がありますOLTPデータベースの主流(たとえば、1秒あたり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_vacuum_cost_delay = 10ms
autovacuum_vacuum_cost_limit = 1000

一般的に積極的な自動バキューム用の完全なプログラムがあります。これは、小さなデータベースが非常に高い更新率を得るのに適している場合がありますが、同時ユーザーアクティビティに大きな影響を与える可能性があります。

また、テーブルごとに自動バキュームパラメータを調整できることに注意してください。これは、ほとんどの場合、自動バキュームの動作を調整する必要がある場合のより良い答えです。

繰り返しますが、実際の問題に対処することはまずありません。


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はシリアル化違反が発生するとトランザクションの1つを中止するため、同時書き込みは問題になりません。

また、テーブル全体ではなくSELECT FOR UPDATEを使用して行をロックすることにより、行をロックできます。

ロックを使用しない別の方法は、トランザクション分離レベルのシリアル化を使用することです。ただし、これは他のトランザクションのパフォーマンスに影響を与える可能性があるため、より多くのシリアル化エラーに備える必要があります。


これは、サマリーテーブルがSHARE ROW EXCLUSIVE MODEを使用してロックされているため、ロックされているためです。ロックなしの同時書き込みは成功する可能性がありますが、間違いなく間違った値で終わる可能性があります。タイプXの行のカウントNを維持していると想像してください。ロックせずにタイプXの2つの行を同時に挿入すると、N + 2ではなくN + 1になります。データベースのサマリーテーブルを手動でバキュームするcronジョブを作成することです。これはうまく機能し、推奨されるアプローチのようですが、私にとってはハックのように感じます。
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

既存の「自動バキュームの資格」スクリプトは非常に便利ですが、(正確に述べたように)テーブル固有のオプションがありませんでした。これらのオプションを考慮に入れた修正版は次のとおりです。

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.