【テクニカル・上級編】 archive_command – PostgreSQL

縁の下の力持ち、`archive_command`と心中しないための作法

PostgreSQLの運用において、`archive_command`ほど「普段は空気のようだが、ひとたび躓くとシステム全体を死に至らしめる」機能はありません。

WAL(Write Ahead Log)のセグメントを安息の地(アーカイブ先)へ運び出すこのプロセス。一見単純なシェルコマンドの実行に見えますが、その裏側にはPostgreSQLの堅牢性を支えるシビアな設計思想が隠されています。今日は、この「アーカイブの深淵」について、運用現場で血を流した経験を交えて少し掘り下げてみましょう。

—

なぜ `archive_command` はブロッキングするのか

まず大前提として理解しておくべきは、`archive_command` は「PostgreSQLのバックグラウンドプロセス(Archiver)が、シェルを同期的に呼び出す」という構造だということです。

PostgreSQLは、WALセグメントが一杯になるたびに、そのファイルを確実にアーカイブ先に転送し終えるまで、そのセグメントの再利用や削除を許可しません。もし `archive_command` が失敗し続けるとどうなるか?

1. pg_wal ディレクトリの肥大化: アーカイブ完了の合図が来ないため、古いWALが永遠に蓄積され続けます。
2. ディスクフルによる全停止: `pg_wal` がディスクを食いつぶし、最終的にはPostgreSQL自体が書き込みを拒否し、シャットダウンへ追い込まれます。

「たかがアーカイブ失敗」と侮っていると、データベースの心臓部を物理的に窒息させることになる。これがこの設定を最も慎重に扱うべき理由です。

失敗時の挙動をハックする

多くの初心者は、コマンドを単に `cp %p /path/to/archive/%f` と書いて満足しますが、本番環境ではこれでは足りません。

  • 終了ステータスへの執着: アーカイブコマンドは、成功時に「0」を返す必要があります。0以外が返されると、PostgreSQLは「失敗」とみなし、無限のリトライループに入ります。
  • アトミック性の確保: アーカイブ先に中途半端なファイルが残るのが一番の悪夢です。`cp` でコピーした後に `mv` でリネームするか、あるいは `rsync –partial` を検討すべきです。転送途中のファイルを誤ってリカバリに使ってしまうリスクを、アーキテクチャのレベルで排除しなければなりません。

パフォーマンスのボトルネック:ボトルネックは「どこ」か?

トラブルシューティングでよくあるのが、「なぜかWALの転送が遅い」という相談です。多くの場合、PostgreSQLの内部というよりは、OSやネットワークのレイヤーに原因があります。

  • IOの競合: `pg_wal` が配置されている物理ディスクと、アーカイブ先(特にNFSやクラウドストレージ)への書き込みが競合していないか。
  • ネットワークスループット: 巨大なトランザクションが多発するシステムでは、WALの生成速度が転送速度を上回ることがあります。これを解消するには、コマンド自体の並列化を考えるのではなく、ストレージのI/Oプロファイルを最適化するのが定石です。

ベテランが実践する「安全な」設定術

もし皆さんが高負荷なデータベースを運用しているなら、`archive_command` をシェルスクリプトのラッパーとして実装することをお勧めします。

!/bin/bash
簡易的なラッパーの例
SOURCE_FILE=$1
DEST_FILE=$2

転送前にファイルが既に存在しないかチェックするなどのバリデーション
失敗時は明確なログを残し、必要に応じてSlackやPagerDutyへ通知を飛ばす
if ! cp “$SOURCE_FILE” “/archive/$DEST_FILE”; then
logger -p local0.err “Archive failed for $SOURCE_FILE”
exit 1
fi
exit 0

単純なワンライナーを避ける理由は、「失敗したときに何が起きたか」を後から追跡できるようにするためです。PostgreSQLのログには「exit code 1」としか出ない場合でも、スクリプト内で `logger` を使っておけば、システムログから詳細な状況を拾い上げることができます。

最後に:アーカイブは「非同期」であるべき

現代的なアーキテクチャでは、`archive_command` への依存度を下げつつ、いかに確実性を高めるかが勝負です。もし可能であれば、`pg_receivewal` のようなストリーミングベースのバックアップ手法を併用し、`archive_command` はあくまで「最後の砦」と位置づけるのが、最も精神衛生上良いアプローチと言えるでしょう。

PostgreSQLは正直なデータベースです。私たちが正しく「データの運び方」を設計してやれば、何年でも文句ひとつ言わずに動き続けてくれます。

皆さんのデータベースに、今日もしっかりとWALが溜まっていますように。それでは、また。

コメント

タイトルとURLをコピーしました