1. 現場の課題:深夜2時の緊急コールとデータ復旧の試練
午前2時15分、けたたましく電話が鳴り響きました。当直エンジニアからの報告は簡潔でした。深夜01:47:30、本番のPostgreSQLクラスタで実行されたマイグレーションの誤りにより、ordersテーブルが誤削除されたとのこと。対象データベースは容量850GB、秒間1,200トランザクションを超える高負荷環境です。
仮に午前00:00時点のpg_dump論理バックアップを使用すると、約2時間分の全取引データが失われてしまいます。しかも850GBのSQLファイルをリストアするには最低でも4〜5時間かかり、RTO(目標復旧時間)もRPO(目標復旧時点)も完全に破綻します。残された唯一の選択肢は、障害発生の1秒前である01:46:59の時点までデータベースを巻き戻すことでした。
2. 従来のバックアップ手法が限界を迎える理由
データベースの規模が数百GBを超えると、従来の手法はすぐにボトルネックに直面します。
- pg_dump / pg_restore: 単一スレッドで動作する論理バックアップです。ダンプおよびリストア処理で大量のCPUとメモリを消費し、インデックスの再構築に数時間単位の時間を要します。何より、ポイントインタイムリカバリ(PITR)に対応していません。
- 標準のpg_basebackup: 物理バックアップではあるものの、マルチプロセスによる並列圧縮機構が組み込まれていません。一時ファイルを保持する中継ディスクをマウントしない限り、S3やMinIOへ直接ストリーミングバックアップを行うことができません。
- 手動のWAL転送スクリプト:
archive_command内でaws s3 cpを呼び出す手法は、書き込みピーク時にI/O詰まりを起こしやすくなります。転送遅延によってWALがローカルディスクを圧迫して容量枯渇を引き起こしたり、ファイル欠落によってリカバリチェーンが完全に破損するリスクがあります。
3. 各種アプローチの比較
大規模システムのバックアップ戦略において、運用チームは主に以下の3つの選択肢を検討します。
- 自作シェルスクリプト(pg_basebackup + AWS CLI): 導入は手軽ですが保守性に難があります。ネットワーク切断時の再開(レジューム)機構がなく、データブロックごとのチェックサム自動検証も行われません。
- WAL-Gの採用: S3への転送速度は極めて優れています。ただし設定構文がやや煩雑で、集中監視が必要なマルチクラスタ(stanza)環境での管理が複雑になりがちです。
- pgBackRestの導入: 現在の本番環境におけるデファクトスタンダードとなる物理バックアップソリューションです。マルチプロセスの並列処理、高速なZstandard圧縮、一時ディスクを介さないS3直接ストリーミング、ブロック単位のSHA-256チェックサム検証、ミリ秒単位の高精度なPITRを標準サポートしています。
4. pgBackRestのセットアップ手順:S3バックアップとPITRリストア
ステップ1:PostgreSQLサーバーへのpgBackRestのインストール
Ubuntu/Debian環境で公式PGDGリポジトリからpgBackRestをインストールします:
sudo apt-get update
sudo apt-get install -y pgbackrest
ステップ2:PostgreSQLでのWALアーカイブ設定
postgresql.confを編集し、継続的なWAL書き込み処理をpgBackRestに委譲します:
# pgBackRest向けのWAL設定
wal_level = replica
archive_mode = on
archive_command = 'pgbackrest --stanza=db-prod archive-push %p'
archive_timeout = 300
max_wal_senders = 5
設定を反映させるためにPostgreSQLを再起動します:
sudo systemctl restart postgresql
ステップ3:AWS S3接続用のpgBackRest設定
/etc/pgbackrest/pgbackrest.confを編集します:
[global]
# Amazon S3ストレージリポジトリの設定
repo1-type=s3
repo1-s3-bucket=prod-postgres-backups-bucket
repo1-s3-endpoint=s3.ap-southeast-1.amazonaws.com
repo1-s3-region=ap-southeast-1
repo1-s3-key=AKIAIOSFODNN7EXAMPLE
repo1-s3-key-secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
repo1-path=/pgbackrest-repo
# パフォーマンス最適化:4プロセス並列実行とZstandard圧縮
process-max=4
compress-type=zst
compress-level=3
# バックアップ保持ポリシー(Retention Policy)
repo1-retention-full=2
repo1-retention-diff=7
# DBクラスタのStanza設定
[db-prod]
pg1-path=/var/lib/postgresql/16/main
pg1-user=postgres
ステップ4:Stanzaの初期化と疎通確認
postgresユーザーでメタデータを作成し、S3への接続テストを実行します:
sudo -u postgres pgbackrest --stanza=db-prod stanza-create
sudo -u postgres pgbackrest --stanza=db-prod check
ターミナルにINFO: check command end: completed successfullyと出力されれば、データベース、アーカイブログ、S3バケット間の連携確認は完了です。
ステップ5:並列バックアップの実行(フル・差分)
初回のフルバックアップを実行します:
sudo -u postgres pgbackrest --stanza=db-prod --type=full backup
process-max=4およびzst圧縮アルゴリズムにより、pgBackRestは4つのワーカーコアを活用してデータを並列に読み取り、ネットワークストリーム経由で直接S3へ転送します。850GBのデータはS3上で約190GBまで圧縮され、所要時間は3.5時間から42分へと大幅に短縮されます。
運用のヒント:データ復旧のデバッグ作業中にテーブル構造をすばやく確認したり、CSVログをJSONに変換・抽出したい場合は、toolcraft.app/ja/tools/data/csv-to-json のツールが便利です。ブラウザ上で直接処理されるため安全に利用できます。
ステップ6:ポイントインタイムリカバリ(PITR)の実践
マイグレーションミス直前の2026-10-02 01:46:59+07の時点へデータベースを復旧させるには、以下の4ステップを順に実行します:
- PostgreSQLサービスを停止します:
sudo systemctl stop postgresql - 既存のデータディレクトリ内をクリアします:
sudo rm -rf /var/lib/postgresql/16/main/* - pgBackRestでPITRリストアコマンドを実行します:
sudo -u postgres pgbackrest --stanza=db-prod \ --type=time \ --target="2026-10-02 01:46:59+07" \ --target-action=promote \ restore - PostgreSQLを起動します:
sudo systemctl start postgresql
PostgreSQLはS3からベースバックアップを自動取得し、指定した時点までの必要なWALレコードをすべて再生(リプレイ)した後、自動でプライマリへプロモートして書き込み受付を再開します。
5. まとめ
pgBackRestとS3ストレージを組み合わせることで、ディスク容量不足の懸念を払拭し、バックアップ時間を劇的に短縮できます。そして何よりも、秒単位で過去の状態を再現できる高精度なPITR機能は、本番環境のデータを守る最も強固なセーフティネットとなります。

