質問と背景
PostgreSQL 18 クラスタが、更新頻度の高い注文テーブルと低頻度のアーカイブテーブルを処理しています。不要タプル(dead tuples)が蓄積し、クエリが遅延し、ディスク I/O スパイクが発生しています。autovacuum ワーカーのキャパシティ管理を設計し、autovacuum_worker_slots、autovacuum_max_workers、テーブル設定、パラレルメンテナンス、およびインシデント時のトレードオフについて説明してください。
面接官が評価するポイント
- ワーカーキャパシティ、同時実行ワーカー数、トリガー閾値、およびコマンドごとの並列度を明確に切り分けているか。
- PostgreSQL 18 の
autovacuum_worker_slotsとそのランタイムチューニングの境界を説明できるか。 - 進行状況ビュー、不要タプル、トランザクション年齢(transaction age)、および I/O メトリクスを使用してボトルネックを特定できるか。
- トランザクション ID ラップアラウンド(TXID wraparound)保護を、レイテンシやディスク圧迫よりも最優先できるか。
まず確認すべき明確化のための質問
ワークロード
データベースおよびテーブルごとの更新、削除、挿入レートはどのくらいですか?ホットテーブルには多数のインデックス、長時間トランザクション、または大量削除がありますか?SLA はクエリレイテンシ、書き込みスループット、ディスク増加量のどれに焦点を当てていますか?
リソース制限
CPU、I/O、メモリ、およびディスク増加の制限はどのようになっていますか?max_worker_processes、max_parallel_workers、maintenance_work_mem、ならびにコンテナまたは VM の制限はどのように構成されていますか?
リスクとリカバリ
クラスタはトランザクション ID ラップアラウンドに近づいていますか?オフピーク時に手動 VACUUM やパーティションのスワップを実行できますか?一時的に書き込みを削減できるテーブルはどれで、監査可能にしておくべき証拠は何ですか?
30秒での回答
テーブルおよびデータベースごとに不要タプルの増加、autovacuum の遅延、トランザクション年齢、および I/O を定量化し、ワーカースロットと通常の同時実行数をサイジングします。ホットテーブルには低めのスケールファクタと適切な閾値を設定し、コールドテーブルでは不要なスキャンを回避します。同時実行数を増やす前に、CPU、I/O、メンテナンスメモリを確認し、進行状況ビューを使用してバックログの解消状況を検証します。ラップアラウンドリスクが最優先事項であり、レート制限や対象を絞った手動メンテナンスは限定的な緊急制御策として行います。
詳細なソリューション
1. リソース階層の把握
autovacuum_worker_slots は、サーバー起動時に autovacuum ワーカー用のバックエンドスロットを予約します。PostgreSQL 18 では通常、カーネルのサポートを前提としてデフォルトで 16 スロットとなります。autovacuum_max_workers は同時実行される autovacuum プロセス数を制限し、有効なスロットプールを超えることはできません。max_worker_processes、CPU、および I/O は共有リソースのままであるため、1つの設定だけを単独でチューニングすることはできません。
2. レイヤードされた同時実行性の設計
許容可能なピーク時のキャパシティプールとして autovacuum_worker_slots を設定し、通常の同時実行性には autovacuum_max_workers を使用します。PostgreSQL 18 では、スロット上限までであれば autovacuum_max_workers をランタイムで変更できますが、スロット自体の変更にはサーバーの再起動が必要です。キャパシティを増やす前に、バックグラウンドプロセス、接続数、およびオペレーティングシステムのセマフォを確保してください。
3. テーブル固有のトリガー設定
グローバルな閾値はベースラインの安全策となります。ホットテーブルでは autovacuum_vacuum_scale_factor を引き下げるか、より適切な autovacuum_vacuum_threshold を設定できます。挿入が多いテーブルには autovacuum_vacuum_insert_threshold も必要です。不要タプルの増加とテーブルサイズに基づいてテーブル個別設定を計算し、小さなテーブルで遅延が発生せず、巨大なテーブルが頻繁にスキャンされすぎないようにします。
4. 1 回の VACUUM のリソース制限
通常の VACUUM は読み書きと並行して実行できますが、I/O を発生させます。max_parallel_maintenance_workers はインデックス構築および FULL を伴わない VACUUM に適用されます。実際のワーカーは max_worker_processes や max_parallel_workers にも制限されます。maintenance_work_mem はユーティリティコマンド全体に適用されますが、並列処理によって CPU と I/O は依然として上昇する可能性があります。
5. ラップアラウンドと長時間トランザクションの処理
通常の autovacuum が無効化されている場合でも、PostgreSQL はトランザクション ID のラップアラウンドを防ぐために必要な処理を起動します。最古のトランザクション年齢、フリーズの進行状況、および VACUUM をブロックしている長時間トランザクションを監視します。ラップアラウンド保護は、通常の遅延ポリシーによってオーバーライドすることはできません。必要に応じて、ブロック元のトランザクションを強制終了し、低優先度のバッチ処理を一時停止して、対象テーブルのメンテナンスを実施します。
6. 実用的なオブザーバビリティの構築
フェーズ、ヒープブロック数、クリーンアップされたブロック数、インデックスサイクル、不要タプルのバイト数、およびコスト遅延の把握には pg_stat_progress_vacuum を使用します。これを pg_stat_all_tables(n_dead_tup、last_autovacuum、last_autoanalyze、テーブルサイズ、トランザクション年齢など)の値と組み合わせて、バックログと完了時間を推定します。低速なタスクの証拠は log_autovacuum_min_duration で保持し、pg_stat_io を使用して autovacuum ワーカーの I/O を分離・特定します。
7. 段階的なチューニングとロールバック
スロットや最大ワーカー数を増やし、CPU、I/O、レイテンシ、バックログを観察するというように、一度に1つのディメンションを変更して進めます。競合が増加した場合は、同時実行数を減らす、テーブルの頻度を下げる、または一括ジョブを再スケジュールします。一時的なバックログを恒久的なキャパシティ不足と誤認しないよう、変更ごとにバージョン、テーブル対象範囲、メトリクスウィンドウ、およびロールバック値を記録します。
優れた回答例
私はワーカースロットをリソースプール、最大ワーカー数を通常の同時実行数、テーブル閾値をワークジェネレーターとして扱います。ホットテーブルには不要タプルの増加に基づいた閾値を設定し、コールドテーブルでは不要なスキャンを避けます。まずワーカーの同時実行性が I/O やクエリレイテンシに与える影響を測定し、段階的に引き上げます。オブザーバビリティでは、進行フェーズ、n_dead_tup、トランザクション年齢、autovacuum ログ、および pg_stat_io を組み合わせます。ラップアラウンドは通常のレイテンシよりも優先され、日常のチューニングよりも前にブロッキングしている長時間トランザクションを処理します。すべての変更にはロールバック記録を残します。
よくある間違い
- スロットを追加せず、または共有ワーカープールを確認せずに
autovacuum_max_workersを増やすこと。 - 起動時に構成されるものであるにもかかわらず、スロットを実際の同時実行数として扱うこと。
- すべてのテーブルに同一のスケールファクタを適用し、小テーブルを遅延させ、大テーブルを過剰にスキャンすること。
- ロックやテーブル再書き込みコストがあるにもかかわらず、
VACUUM FULLを日常のメンテナスとして使用すること。 - ディスクスペースのみを監視し、トランザクション年齢、不要タプル、進行フェーズを無視すること。
- レイテンシのために autovacuum を無効化し、ラップアラウンド保護を忘れること。
フォローアップの質問と回答
autovacuum_worker_slots と autovacuum_max_workers の違いは何ですか?
前者は起動時にワーカーのバックエンドスロットを予約するもので、後者は同時に実行される autovacuum プロセス数を制限するものです。最大ワーカー数を有効スロット以上に設定しても、その同時実行数は得られません。PostgreSQL 18 では、スロット制限の範囲内であれば最大ワーカー数をランタイムで変更できます。
同時実行数を増やすと VACUUM は高速化しますか?
自動的にそうなるわけではありません。メンテナンス時間は短縮されるかもしれませんが、CPU、I/O、およびアプリケーションとの競合が増加する可能性があります。バックログ完了時間、クエリレイテンシ、および I/O ピークを総合して判断してください。
なぜテーブル固有のスケールファクタを使用するのですか?
割合による指定は、大規模テーブルでは膨大な絶対数の不要タプルにつながり、小規模テーブルではトリガーがまばらになりすぎる可能性があります。テーブル個別のオーバーライドにより、更新レート、サイズ、および SLA に作業を適合させることができます。
I/O がワーカーを遅延させていることをどのように証明しますか?
pg_stat_progress_vacuum のフェーズと遅延時間を使用し、pg_stat_io 内の autovacuum ワーカー行をディスクレイテンシおよびアプリケーションのクエリメトリクスと相関させ、同一の時間枠で比較します。
ラップアラウンド処理を最優先すべきなのはどのような場合ですか?
最古のトランザクション年齢が保護閾値に近づいた場合、フリーズの進行が遅れている場合、またはクラスタがラップアラウンド防止 autovacuum を実行している場合は、ブロッカーを排除してフリーズ処理を最優先で完了させます。通常のビジネスタスクのチューニングはそのリスク対応に譲る必要があります。