PostgreSQLのバックアップといえばpg_dumpです。コマンド1つでデータベースの中身を書き出せる、手軽で確実なツールです。

ところが、いざ復元する段になって次のような事態に直面することがあります。

  • 復元しようとしたらファイル形式が違うと言われた
  • server version mismatchというエラーで実行すらできない
  • 復元は成功したのにユーザー(ロール)が存在しない
  • 障害発生の直前まで戻せず、前回取得時点までのデータが失われた

いずれもpg_dumpの仕様どおりの挙動です。バックアップは取得できたかどうかより、復元できるかどうかが重要なので、事前に押さえておく必要があります。

pg_dumpは何を保存し、何を保存しないのか。

公式ドキュメントをもとに整理します。

pg_dump の基本動作

まず優れている点から。pg_dumpはサービスを止めずに実行できます。

pg_dumpは、データベースが同時に使用されていても一貫したエクスポートを行う。pg_dumpは他のユーザーのデータベースへのアクセス(読み取り・書き込みとも)をブロックしない

実行中もアプリケーションは通常どおり動き、取得されるデータは開始時点の一貫した状態になります。途中で更新が入っても、中途半端な状態が混ざることはありません。

一方で、対象範囲には明確な制限があります。

pg_dumpは単一のデータベースのみをダンプする。クラスタ全体をエクスポートする場合、またはクラスタ内のすべてのデータベースに共通するグローバルオブジェクト(ロールやテーブルスペースなど)をエクスポートする場合は、pg_dumpallを使用する

この一文が、後述する「復元したのにユーザーがいない」の答えです。

【重要】公式は「定期バックアップには向かない」と述べている

意外に知られていませんが、公式ドキュメントはpg_dumpの位置づけについて注意を促しています。

ただし、単純なケースを除き、pg_dumpは一般に本番データベースの定期的なバックアップを取得するための適切な選択ではない

理由は、pg_dumpが取得した瞬間のスナップショットでしかないことにあります。

毎日深夜にpg_dumpを実行している環境で、夕方に障害が起きたとします。復元できるのはその日の深夜時点までで、日中に発生したデータはすべて失われます。

PITR(ポイントインタイムリカバリ)との違い

PostgreSQLには、この弱点を補う仕組みがあります。継続的アーカイブと呼ばれる方式です。

WALエントリを最後まで再生する必要はない。任意の時点で再生を止め、その時点のデータベースの一貫したスナップショットを得ることができる。したがってこの技術はポイントインタイムリカバリをサポートする。ベースバックアップ取得以降の任意の時点の状態にデータベースを復元することが可能である

WAL(更新ログ)を継続的に保存しておくことで、「障害が起きる1分前」といった任意の時点に戻せます

pg_dump 継続的アーカイブ(PITR)
戻せる時点 取得した瞬間のみ 任意の時点
導入の手間 コマンド1つ 設定と運用が必要
向く用途 移行・検証環境の複製 本番の障害対策

なお、公式は継続的アーカイブについても注意点を挙げています。設定ファイル(postgresql.confやpg_hba.confなど)への変更は復元されないという点です。設定ファイルは別途バックアップが必要になります。

クラウドのマネージドDBを使っていても、責任共有モデルのもとでデータの保全は利用者側の責任範囲に含まれます。自動バックアップの保持期間と復元可能な時点を、必ず確認してください。

4つの出力形式と、復元コマンドの違い

「形式が違う」というエラーの原因はここにあります。pg_dumpは-Fオプションで4つの形式を選べます。

形式 指定 復元コマンド 特徴
plain -Fp(既定) psql テキストのSQL文
custom -Fc pg_restore 既定で圧縮・項目を選んで復元可
directory -Fd pg_restore 並列ダンプに対応
tar -Ft pg_restore directory形式と互換

重要なのは復元コマンドが2種類に分かれることです。既定のplain形式はpsqlで流し込みますが、それ以外はpg_restoreを使います。ここを取り違えるとエラーになります。

どれを選ぶべきか

公式はcustom形式についてこう説明しています。

directory出力形式とともに、これは最も柔軟な出力形式である。復元時にアーカイブされた項目を手動で選択し、並べ替えることができるためである。この形式は既定で圧縮される

「テーブルを1つだけ戻したい」といった場面で威力を発揮します。plain形式はただのテキストファイルなので、一部だけを復元するには手作業での編集が必要です。

directory形式は並列ダンプに対応している点が特徴で、大規模なデータベースでは取得時間を短縮できます。

特別な理由がなければ-Fc(custom)を選んでおくと扱いやすいでしょう。

pg_dump に含まれないもの

「復元したのにログインできない」の原因がこれです。pg_dumpが出力するのは1つのデータベースの中身だけで、次のものは含まれません。

  • ロール(ユーザーとパスワード)
  • テーブルスペース
  • 他のデータベース

これらはデータベース単位ではなく、クラスタ全体で共有されるグローバルオブジェクトだからです。復元するには、別途pg_dumpallで取得しておく必要があります。

-g--globals-onlyグローバルオブジェクト(ロールとテーブルスペース)のみをダンプし、データベースは含めない

実務では、データベース本体と合わせて2種類のバックアップを取得するのが基本になります。片方だけでは、別サーバーへの移行時に権限設定を手作業で復旧することになります。

バージョンの制約

server version mismatchエラーの正体です。pg_dumpにはバージョンの上下関係に明確なルールがあります。

pg_dumpは自身のバージョンより古いPostgreSQLサーバーからダンプできる(現在、バージョン9.2まで対応)。しかし、pg_dumpは自身のメジャーバージョンより新しいサーバーからはダンプできない。無効なダンプを作る危険を冒すよりも、試すことすら拒否する

整理すると次のようになります。

状況 可否
新しいpg_dump → 古いサーバーからダンプ 可能
古いpg_dump → 新しいサーバーからダンプ 拒否される
ダンプ結果 → 新しいサーバーへ復元 想定された使い方
ダンプ結果 → 古いサーバーへ復元 保証されない

つまりpg_dumpは常にサーバーと同じか、それより新しいものを使うのが原則です。クライアント側のPostgreSQLだけ古いままだと、サーバーをアップグレードした瞬間にバックアップが取れなくなります。

公式は最後の行についても明記しています。「pg_dumpの出力がより古いメジャーバージョンのサーバーにロードできる保証はない——たとえそのバージョンのサーバーから取得したダンプであっても」。ダウングレード方向の移行は、想定されていません。

実務での指針

  • 形式は-Fcを基本にする。復元時の柔軟性が高く、圧縮も効きます
  • pg_dumpallでグローバルオブジェクトも取得する。ロールを忘れると移行時に困ります
  • pg_dumpはサーバーと同じか新しいバージョンを使う
  • 本番の障害対策にはPITRを検討する。pg_dumpだけでは前回取得時点までしか戻せません
  • 復元の手順を実際に試しておく。取得できていても復元できなければ意味がありません

最後の項目が最も重要です。ランサムウェア対策の観点でも、復元テストを行っていないバックアップは「あるつもり」でしかありません。

よくある質問

Q. pg_dumpの実行中にサービスを止める必要はありますか?

不要です。公式にあるとおり、読み書きをブロックしません。ただしCPUとI/Oは消費するため、負荷の低い時間帯に実行するのが無難です。

Q. 特定のテーブルだけ復元できますか?

custom形式またはdirectory形式で取得していれば、pg_restoreのオプションで対象を選べます。plain形式の場合はSQLファイルを直接編集することになります。

Q. データベースが大きく、取得に時間がかかります

directory形式で並列ダンプを使うと短縮できます。ただし並列実行はサーバーへの負荷が増えるため、同時実行数の調整が必要です。

Q. pg_dumpallだけ使えばよいのでは?

pg_dumpallはクラスタ全体を出力できますが、形式がplain(テキスト)に限られます。圧縮や部分復元の柔軟性が失われるため、実務ではグローバルオブジェクトの取得に用い、データ本体はpg_dumpで取得する組み合わせが一般的です。

Q. 復元後に動作が遅くなりました

統計情報が失われているためです。公式も復元後にANALYZEを実行するよう案内しています。

参考にした主な調査・資料

  • pg_dump(PostgreSQL公式ドキュメント)— 動作仕様、出力形式、バージョン間の互換性、定期バックアップに関する注意
  • pg_dumpall(PostgreSQL公式ドキュメント)— グローバルオブジェクトの取得と--globals-onlyの仕様
  • Continuous Archiving and Point-in-Time Recovery (PITR)(PostgreSQL公式ドキュメント)— 任意時点への復元の仕組みと、設定ファイルが対象外である点

まとめ

pg_dumpは手軽ですが、前提を理解して使う必要があります。

  • 実行中も読み書きをブロックしない。一貫した状態で取得できる
  • 公式は本番の定期バックアップには適さないとしている。戻せるのは取得時点のみ
  • 任意の時点に戻すには継続的アーカイブ(PITR)が必要
  • 形式は4種類。plainはpsql、それ以外はpg_restoreで復元する
  • ロールとテーブルスペースは含まれない。pg_dumpallでの取得が必要
  • pg_dumpは自身より新しいサーバーからはダンプできない
  • 復元後はANALYZEを実行する

バックアップの良し悪しは、取得した時点ではなく復元を試した時点で初めて分かります。手順書を作り、一度は実際に戻してみてください。