高WALアクティビティのトラブルシューティングとアーカイブログディスク容量管理

PostgreSQLにおける過剰な先行書き込みログ(WAL)生成のトラブルシューティングと管理方法を学びます。このガイドでは、一括操作やレプリケーション問題など、高WALアクティビティの一般的な原因を解説し、WALアーカイブ設定、レプリケーションスロット管理、ディスク容量枯渇防止の実践的な解決策を提供します。安定性と効率的なディスク容量利用に重点を置くPostgreSQL管理者にとって必読の内容です。

高WALアクティビティのトラブルシューティングとアーカイブログディスク容量管理

PostgreSQLにおける高WAL(Write-Ahead Log)アクティビティは、必ずしも問題ではありません。ビジーなデータベースはWALを生成するものです。問題は、WALの発生率が予想外に高い場合、アーカイブされたWALがクリーンアップされない場合、または何かがPostgreSQLによる古いセグメントのリサイクルを妨げているためにpg_walが肥大化する場合です。

WALインシデントを悪化させる最速の方法は、pg_walから手動でファイルを削除することです。絶対に行わないでください。WALディスクの満杯は復旧状況として扱い、WALを保持している原因を特定し、安全に可能であれば余裕を作り、その後、障害が発生したアーカイブ、遅延しているスタンバイ、または成長の原因となった放棄されたスロットを修正してください。

先行書き込みログ(WAL)の理解

PostgreSQLは、関連するデータページが安全に書き込まれる前に、変更レコードをWALに書き込みます。クラッシュ後、PostgreSQLはWALを再生して、コミットされた変更が失われないようにします。同じストリームは、ストリーミングレプリケーションやポイントインタイムリカバリにも使用されます。

WALファイルは固定サイズのセグメントファイルに保存されます。多くのインストールでは、一般的なデフォルトである16 MBセグメントを使用しますが、サイズはクラスターの初期化時に選択されます。書き込み負荷の高いワークロードでは、多数のセグメントが急速に作成される可能性があります。古いセグメントは、PostgreSQLがクラッシュリカバリ、チェックポイント、アーカイブ、レプリケーション、またはスロットに必要としなくなった後にのみリサイクルまたは削除されます。

WALの主要な概念:

  • 永続性: コミットされたトランザクションはクラッシュ後も復旧可能です。
  • レプリケーション: スタンバイはプライマリからWALレコードを受信します。
  • ポイントインタイムリカバリ(PITR): ベースバックアップとアーカイブされたWALにより、保持期間内の任意の時点に復旧できます。
  • WALセグメント: WALはpg_walディレクトリ内のセグメントファイルに保存されます。

高WALアクティビティの一般的な原因

いくつかの要因が異常に高いWAL生成量に寄与する可能性があります。根本原因を特定することが、効果的なトラブルシューティングの第一歩です。

1. 一括データロードと変更

INSERTUPDATEDELETETRUNCATECOPYなどの操作は、大量のWALを生成する可能性があります。特に大規模なテーブルに対する一括操作は、小規模な個別トランザクションよりも自然に多くのWALレコードを生成します。

  • 例: 数百万行を挿入する単一のCOPY FROMコマンドは、ギガバイト単位のWALデータを生成する可能性があります。
  • 例: 大規模なデータ移行やバッチ更新スクリプトの実行。

2. レプリケーション遅延とスタンバイの問題

スタンバイサーバーがプライマリに追いついていない場合(レプリケーション遅延)、WALファイルがプライマリに蓄積されます。プライマリサーバーは、完了したWALセグメントが接続されているすべてのスタンバイに送信され処理されたことが確認されるまで、それらを削除できません(wal_keep_sizemax_slot_wal_keep_sizeが設定されていない場合、またはスロットが正しく使用されていない場合)。

  • シナリオ: スタンバイサーバーがダウンしている、切断されている、またはパフォーマンスの問題が発生しており、プライマリからのWALレコードの消費が妨げられている。

3. チェックポイント後のフルページ書き込み

チェックポイント後、full_page_writesが有効になっている場合、データページへの最初の変更はフルページイメージをログに記録する可能性があります。この設定は、リカバリ中のページ破損から保護するため、通常は有効のままにします。チェックポイントが頻繁に発生する場合、フルページイメージによりWAL容量が顕著に増加する可能性があります。修正方法は通常、耐久性保護を無効にするのではなく、チェックポイント動作を調整することです。

4. 管理されていないpg_walディレクトリの成長

WALアーカイブが有効で失敗している場合、PostgreSQLはまだアーカイブが必要なWALセグメントを保持します。アーカイブが有効でない場合、pg_walは不要になった古いセグメントをリサイクルするはずですが、レプリケーション、スロット、またはチェックポイントのプレッシャーが保持している場合は除きます。

5. 解放されていないレプリケーションスロット

レプリケーションスロットは、特定のスタンバイまたは論理デコードクライアントによって消費されるまでWALセグメントが削除されないことを保証します。スロットが作成されたが、コンシューマーが停止または切断され、スロットが削除されない場合、そのスロットが必要とするWALセグメントは、スタンバイがもはやアクティブでなくても保持されます。

WALディスク容量の管理:設定と解決策

高WALアクティビティに対処するには、監視、設定調整、適切なメンテナンス手順を含む多面的なアプローチが必要です。

1. WALアーカイブの有効化と監視

WALアーカイブは、ディスク容量を管理しPITRを有効にするための最も重要なメカニズムです。アーカイブが有効な場合、完了したWALファイルは別の場所(例:ネットワークファイル共有、S3バケット、別のディスク)にコピーされます。

設定:

postgresql.confファイルを変更します:

wal_level = replica         # 論理レプリケーションの場合はlogical
archive_mode = on           # アーカイブを有効化
archive_command = 'cp %p /path/to/archive/%f'

# wal-gなどのツールを使用したS3の例:
# archive_command = 'wal-g wal-push %p'
  • %p:アーカイブするWALファイルのフルパスのプレースホルダー。
  • %f:WALファイルのファイル名のプレースホルダー。

重要: archive_commandは正常に実行できる必要があります。ゼロ以外の終了コードを返す場合、PostgreSQLはアーカイブが失敗したと見なし、WALファイルが削除されない可能性があります。宛先ディレクトリに十分な空き容量があり、PostgreSQLを実行するユーザーに書き込み権限があることを確認してください。

アーカイブの監視

SQLクエリを使用してアーカイブのステータスを確認します:

SELECT archived_count,
       failed_count,
       last_archived_wal,
       last_archived_time,
       last_failed_wal,
       last_failed_time
FROM pg_stat_archiver;

failed_countが増加し続けている場合、またはデータベースが書き込み中であるにもかかわらずlast_archived_timeが古い場合は、WALサイズパラメータを調整する前にアーカイブ先を修正してください。

2. pg_walディレクトリサイズの管理

アーカイブが有効でも、WALセグメントがアーカイブ後に削除されない場合、プライマリのpg_walディレクトリが肥大化する可能性があります。これは以下の場合に発生します:

  • スタンバイが追いついておらず、プライマリがレプリケーション用に余分なWALを保持している。
  • レプリケーションスロットがWALファイルを保持している。

wal_keep_size

このパラメータは、ストリーミングレプリケーション用にプライマリに余分なWALを保持します。PostgreSQL 13では、古いwal_keep_segments設定を置き換えました。スロットを使用しないスタンバイには便利ですが、大幅に遅延しているスタンバイが常に追いつけることを保証するものではありません。

# プライマリのpostgresql.conf
wal_keep_size = 1024 # 1GBのWALをディスクに保持

特定のコンシューマー用にWALを保持する必要がある場合、レプリケーションスロットが好まれることがよくありますが、スロットはWALを無期限に保持する可能性があるため、監視する必要があります。

max_slot_wal_keep_size(PostgreSQL 13以降)

この設定は、レプリケーションスロットが保持できるWALの量を制限します。これは、壊れたスロットによる無制限の成長に対するガードレールですが、遅延しているコンシューマーが必要なWALを失い、再初期化が必要になる可能性もあります。

# プライマリのpostgresql.conf
max_slot_wal_keep_size = 2048 # スロットが保持するWALを2GBに制限

# 次の設定も検討:wal_keep_size -- スロットベースでないストリーミングには依然として関連
# wal_keep_size = 1024 # 非スロットストリーミング用に1GBを保持

スロットが大幅に遅れ、この制限を超えた場合、PostgreSQLはチェックポイント時に必要なWALを削除する可能性があります。これによりディスク容量は保護されますが、影響を受けるスタンバイや論理レプリケーションクライアントは、古い位置から続行できなくなる可能性があります。

レプリケーションスロット

レプリケーションスロットは、WALの損失を防ぎ、信頼性の高いレプリケーションを確保するために重要です。ただし、正しく管理されないとWALファイルが蓄積される原因になります。

  • 問題: レプリケーションスロットが作成されたが、コンシューマー(スタンバイまたは論理クライアント)が切断または障害を起こし、スロットが削除されない。プライマリサーバーは、スロットが待機しているすべてのWALファイルを保持し続けます。
  • 解決策: レプリケーションスロットを定期的に監視し、使用していないスロットを削除します。
-- レプリケーションスロットの一覧表示
SELECT slot_name,
       plugin,
       slot_type,
       active,
       restart_lsn,
       wal_status,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC NULLS LAST;

-- 未使用のスロットを削除
SELECT pg_drop_replication_slot('slot_name_to_drop');

警告: レプリケーションスロットを削除すると、接続されているコンシューマーはその位置を失います。削除する前に、コンシューマーが不要であること、または適切に再初期化されていることを確認してください。

3. min_wal_sizemax_wal_sizeの調整

これらのパラメータは、チェックポイントの頻度と、PostgreSQLが再利用のために保持しようとするWALの量に影響を与えます。アーカイブやレプリケーションのために保持されるWALを制限するものではありません。

  • min_wal_size:PostgreSQLがすぐに削除する代わりに、少なくともこの量のWALを再利用のために保持するよう促します。
  • max_wal_size:チェックポイントをトリガーする傾向があるWALボリューム。他の理由でWALが保持されている場合、ハードな最大値ではありません。
# postgresql.conf
min_wal_size = 1GB
max_wal_size = 4GB

max_wal_sizeを増やすと、ピーク書き込み負荷時にシステムにより多くの余裕を与えることができますが、事前割り当てされたWALファイルにより多くのディスク容量が占有されることも意味します。

4. アーカイブされたWALファイルの定期的なクリーンアップ

WALアーカイブはリカバリに不可欠ですが、アーカイブされたファイルがクリーンアップされない場合、ディスク容量の問題を引き起こす可能性もあります。アーカイブされたWALファイルの保持を管理する戦略が必要です。

  • 戦略: スクリプトを実装するか、専用ツール(pg_archivecleanuppgBackRestwal-gbarmanなど)を使用して、PITRやレプリケーションに不要になった古いWALファイルをアーカイブ場所から削除します。

  • pg_archivecleanupの使用: このユーティリティはプライマリサーバーで実行でき、アーカイブディレクトリから古いWALファイルを削除します。

    pg_archivecleanup /path/to/archive/location 0000000100000037000000AF
    

    2番目の引数は、保持する必要がある最も古いWALファイル名であり、任意の経過時間ではありません。実際には、pgBackRest、Barman、WAL-Gなどのバックアップツールは、バックアップ保持とリカバリに必要なWALを理解しているため、より安全です。

    重要: クリーンアップ戦略が、バックアップおよびリカバリのポイントインタイムリカバリ(PITR)要件と常に一致していることを確認してください。目的のリカバリウィンドウをカバーするのに十分な期間、WALファイルを保持する必要があります。

5. ディスク容量とWAL生成レートの監視

プロアクティブな監視は、ディスク容量の枯渇を防ぐ鍵です。

  • ディスク容量の監視: データディレクトリ、pg_wal、一時ファイルの場所、アーカイブ先の空き容量を追跡します。

  • WAL生成の監視: 時間経過に伴うLSNの差を使用して、生成レートを推定します。

    SELECT now() AS sample_time,
           pg_current_wal_lsn() AS current_lsn;
    

    その値を定期的に保存し、pg_wal_lsn_diff(new_lsn, old_lsn)でサンプルを比較します。現在のpg_walディレクトリサイズを簡単に確認するには:

    SELECT pg_size_pretty(sum(size)) AS pg_wal_size
    FROM pg_ls_waldir();
    

ディスク満杯時のトラブルシューティング手順

WALアクティビティによりディスクがすでに満杯の場合は、即時対応が必要です:

  1. 原因の特定: pg_stat_archiverでアーカイブの失敗を確認します。pg_replication_slotsで未使用または問題のあるスロットを調べます。スタンバイのレプリケーション遅延を確認します。
  2. リカバリを損なわずに容量を解放:
    • pg_walから手動でファイルを削除しないでください。
    • アーカイブ先が満杯の場合は、バックアップ保持期間外の古いアーカイブWALのみを削除します。
    • 可能であれば、ストレージを追加するかアーカイブ先を移動し、PostgreSQLが通常どおりアーカイブおよびリサイクルできるようにします。
  3. 根本原因に対処:
    • アーカイブの修正: archive_commandが正しく、宛先に空き容量があることを確認します。
    • スロットの管理: 未使用のレプリケーションスロットを削除します。
    • レプリケーションの修正: スタンバイ遅延を引き起こしている問題に対処します。
    • ディスク容量の増加: 一時的または恒久的にストレージを追加します。
  4. アーカイバを促す: アーカイブコマンドまたは宛先を修正した後、PostgreSQLは再試行するはずです。設定変更にはリロードで十分な場合が多く、ディスクインシデント中はフル再起動は最後の手段にすべきです。

より安全なメンタルモデル

pg_walが成長している場合、順番に3つの質問を自問してください:

  1. ワークロードが変更されたため、PostgreSQLは通常よりも多くのWALを生成していますか?
  2. PostgreSQLはWALをアーカイブできませんか?
  3. PostgreSQLはレプリケーションまたはスロットのためにWALを保持するように指示されていますか?

これらの答えは異なる修正方法を示します。一括書き込みは、スケジューリング、バッチ処理、またはチェックポイント調整が必要な場合があります。アーカイブの失敗は、ストレージとコマンドの修正が必要です。スロット保持は、コンシューマーの復旧、スロットのクリーンアップ、または保持制限が必要です。max_wal_sizeを推測しても、それだけで実際の問題を解決することはほとんどありません。