PostgreSQLは常に、クラスタのデータディレクトリ以下のpg_wal/
ディレクトリ内で先行書き込みログ(WAL)を管理しています。
このログはデータベースのデータファイルに行われた全ての変更を記録します。
このログは主にクラッシュ時の安全性を目的としています。
システムがクラッシュしたとしても、最後のチェックポイント以降に作成されたログ項目を「やり直し」することで、データベースを整合性を維持した状態にリストアすることができます。
しかし、この存在するログファイルを使用して、データベースのバックアップ用の第3の戦略が可能になりました。
ファイルシステムレベルのバックアップとWALファイルのバックアップを組み合わせるという戦略です。
復旧が必要ならば、ファイルシステムバックアップをリストアし、その後にバックアップされたWALファイルを再生することで、システムを最新の状態にできます。
管理者にとって、この方法はこれまで説明した方法よりかなり複雑になりますが、以下のような大きな利点が複数あります。
開始時点のファイルシステムバックアップは完全な整合状態である必要はありません。 そのバックアップ内の内部的な不整合はログのやり直しによって修正されます (これは、クラッシュからの復旧時に行われることと大きな違いはありません)。 ですので、ファイルシステムのスナップショット機能を必要としません。 単にtarなどのアーカイブツールが必要です。
再生の際にWALファイルの並びを数に制限なく連ねて組み合わせられますので、単にWALファイルのアーカイブを続けることで連続したバックアップを達成できます。 これは、頻繁に完全なバックアップを行うことが困難な、大規模なデータベースでは特に価値があります。
WAL項目の再生を最後まで行わなければならないということはありません。 やり直しを任意の時点までで停止することができ、それにより、その時点までのデータベースの整合性を持ったスナップショットを得ることができます。 このような技術がポイントインタイムリカバリを補助するものであり、元となるベースバックアップの取得時点以降の任意の時点の状態にデータベースをリストアすることが可能になります。
連続的に一連のWALファイルを、同一のベースバックアップをロードしている別のマシンに配送することで、ウォームスタンバイシステムを保有することができます。 つまり、任意の時点でその2番目のマシンを、ほぼ現時点のデータベースの複製を持った状態で有効にすることができます。
pg_dumpとpg_dumpallはファイルシステムレベルのバックアップを生成しませんので、継続的アーカイブ方式の一部として使うことはできません。 そのダンプは論理的なものであり、WALのやり直しで使うのに十分な情報を含んでいません。
通常のファイルシステムバックアップ技術の場合と同様、この方法は、一部ではなく、データベースクラスタ全体のリストア処理のみをサポートできます。 また、アーカイブ用に大量の格納領域を必要とします。 ベースバックアップはかさばる場合があり、また、高負荷なシステムではアーカイブしなければならないWALの流量をメガバイト単位で生成します。 しかし、これは、高信頼性が必要な、多くの状況でむしろ好まれるバックアップ手法です。
継続的アーカイブ(多くのデータベースベンダで「オンラインバックアップ」とも呼ばれます)を使用して復旧を成功させるためには、少なくともバックアップの開始時点まで遡る、連続した一連のアーカイブ済みWALファイルが必要です。 ですので、運用するためには、最初のベースバックアップを取得する前にWALファイルをアーカイブする手順を設定し試験しなければなりません。 したがって、まずWALファイルのアーカイブ機構について説明します。
抽象的な意味では、実行中のPostgreSQLシステムは無限に長い一連のWALレコードを生成します。 システムは物理的にこの並びを、通常1つ16メガバイト(このセグメントサイズはinitdbの実行時に変更可能です)の、WALセグメントファイルに分割します。 このセグメントファイルには、概念的なWALの並び内の位置を反映した、数字の名前が付与されます。 WALアーカイブを行わない場合、システムは通常数個のセグメントファイルを生成し、不要となったセグメントファイルの名前をより大きなセグメント番号に変更することでそれを「リサイクル」します。 最後のチェックポイントより前の内容を持つセグメントファイルはもはや重要でなく、リサイクルできると見なされます。
WALデータをアーカイブする場合、完成したセグメントファイルのそれぞれの内容を取り出し、再利用のために回収される前にそのデータをどこかに保存することが必要です。
アプリケーションと利用できるハードウェアに依存しますが、数多くの「データをどこかに保存する」方法があります。
例えば、NFSでマウントした他のマシンのディレクトリにセグメントファイルをコピーすること、あるいは、テープ装置に書き出すこと(元々のファイル名を識別する手段があることを確認してください)、それらを一度にまとめてCDに焼くこと、そのほか全く異なったなんらかの方法などです。
柔軟性をデータベース管理者に提供するために、PostgreSQLは、どのようにアーカイブがなされたかについて一切想定しないようになっています。
その代わりにPostgreSQLは、管理者に完全なセグメントファイルをどこか必要な場所にコピーするシェルコマンドあるいはアーカイブライブラリを指定させます。
このコマンドは単純なcp
を使ったシェルコマンドでも構いませんし、また、複雑なC関数を呼び出しても構いません。
全て管理者に任されています。
WALアーカイブを有効にするには、wal_level設定パラメータをreplica
以上に、archive_modeをon
に設定し、archive_command設定パラメータで使用するシェルコマンドを指定するか、archive_library設定パラメータで使用するライブラリを指定します。
実際には、これらの設定は常にpostgresql.conf
ファイルに置かれます。
archive_command
では、%p
はアーカイブするファイルのパス名に置き換えられますが、%f
はファイル名のみに置き換えられます。
(パス名は現在の作業ディレクトリ、つまりクラスタのデータディレクトリからの相対パスです。)
実際の%
文字をコマンドに埋め込む必要がある場合は%%
を使用してください。
最も簡単で便利なコマンドは以下のようなものです。
archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' # Unix archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"' # Windows
これは、アーカイブ可能なWALセグメントを/mnt/server/archivedir
ディレクトリにコピーします
(これは一例です。
推奨するものではなく、また、全てのプラットフォームで動作しない可能性があります)。
%p
および%f
パラメータが置き換えられたあと、実行された実コマンドは以下のようになります。
test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065
類似したコマンドがアーカイブされるそれぞれの新規ファイルに生成されます。
このアーカイブ用コマンドはPostgreSQLサーバを稼働させるユーザと同じ所有権で実行されます。 アーカイブされる一連のWALファイルには、実質、データベース内の全てが含まれていますので、アーカイブしたデータをのぞき見から確実に保護しなければならないでしょう。 例えば、グループや全員に読み込み権限を付与していないディレクトリにデータをアーカイブしてください。
アーカイブ用コマンドが成功した場合のみにゼロという終了ステータスを返すことが重要です。 PostgreSQLは、ゼロという結果に基づいて、そのファイルのアーカイブが成功したことを想定し、そのファイルを削除したり回収するかもしれません。 しかし、非ゼロのステータスは、PostgreSQLに対してファイルがアーカイブされなかったことを通知し、成功するまで定期的に再試行させます。
アーカイブするための別の方法は、archive_library
としてカスタム・アーカイブ・モジュールを使用することです。
このようなモジュールはC
で記述されているため、独自のモジュールを作成するには、シェル・コマンドを記述するよりもかなり多くの労力が必要になる場合があります。
しかし、アーカイブ・モジュールはシェルを介したアーカイブよりもパフォーマンスが高く、多くの有用なサーバー・リソースにアクセスできます。
アーカイブ・モジュールの詳細は第51章を参照してください。
アーカイブコマンドがシグナル(サーバのシャットダウンの一部として使用されるSIGTERM以外)やシェルによる125以上の終了ステータスを持つエラー(command not foundなど)、あるいはアーカイブ関数がERROR
またはFATAL
を出力したことによって終了すると、アーカイバプロセスは中止され、postmasterによって再起動されます。
このような場合、失敗はpg_stat_archiverでは報告されません。
通常アーカイブ用コマンドあるいはライブラリは、既存のアーカイブ済みファイルの上書きを行わないように設計されなければなりません。 これは、管理者のミス(例えば2つの異なるサーバの出力を同一のアーカイブ用ディレクトリに送信してしまうなど)といった場合からアーカイブ状況の整合性を保護するための安全策として重要です。
使用予定のアーカイブ用コマンドあるいはライブラリが、当然のことながら既存のファイルを上書きしないこと、かつ、上書きしようとした場合には非ゼロのステータスあるいはfalse
をそれぞれ返すことを確認するために試験することを勧めます。
上のUnix用のコマンド例では、別途test
という段階を含めることでこれを確認しています。
いくつかのUnixプラットフォームではcp
コマンドには-i
引数を使うことで煩雑な出力を少なくし使うことができますが、正しい終了コードが返ることを確認せずに使用するべきではありません。
(具体的にはGNUのcp
コマンドは-i
オプションを使い、ターゲットファイルがすでに存在している場合、ゼロのステータスを返します。これは期待していない動作です。)
アーカイブ設定を設計する時には、操作者の介入が必要であったり、アーカイブ場所の容量不足の理由でアーカイブ用コマンドあるいはライブラリが繰り返し失敗した時にどうなるかを考慮してください。
例えば、これはオートチェンジャ機能のないテープに書き出している場合に発生する可能性があります。
テープが一杯になった場合、テープを交換するまでアーカイブを行うことができなくなります。
こうした状況を相応の早さで解消できるよう、適切に操作者に対しエラーや要求を確実に連絡できるようにしなければなりません。
この状況が解消するまで、WALセグメントファイルはpg_wal/
ディレクトリ内に格納され続けます。
(pg_wal/
を含むファイルシステムがいっぱいになると、PostgreSQLはパニック停止します。コミットされたトランザクションは失われませんが、データベースはいくらかの容量を解放するまでオフラインのままです。)
サーバのWALデータの生成に要する平均速度に追いついている限り、アーカイブ用コマンドあるいはライブラリの処理速度は重要ではありません。
アーカイブプロセスが多少遅れたとしても通常の操作は続けられます。
アーカイブ処理がかなり遅れると、災害時に損失するデータの量が増加することになります。
また、これはpg_wal/
ディレクトリ内に多くのアーカイブ処理待ちのセグメントファイルが格納され、ディスク容量が不足する状況になる可能性があることを意味します。
アーカイブ処理が確実に意図通りに動作しているかを監視することを推奨します。
アーカイブ用コマンドあるいはライブラリを作成する時、アーカイブされるファイル名は最長64文字までで、ASCII文字と数字とドットのどんな組合せを使用しても構いません。
元の相対パス(%p
)を保存する必要はありませんが、ファイル名(%f
)を保存する必要はあります。
WALアーカイブによってPostgreSQLデータベースでなされた変更は全てリストアすることができますが、設定ファイルはSQL操作ではなく手作業で変更されますので、設定ファイル(postgresql.conf
、pg_hba.conf
、およびpg_ident.conf
)になされた変更までリストアしないことに注意してください。
通常のファイルシステムバックアップ手続きでバックアップされる場所に設定ファイルを保持したい場合があります。
設定ファイルの設置場所を変更するには20.2を参照してください。
アーカイブコマンドあるいは関数は完全なWALセグメントに対してのみ呼び出されます。
このため、サーバが少ししかWAL流量がない(処理を行わないなぎの期間がある)場合、トランザクションの完了とアーカイブ格納領域への安全な記録との間に長期にわたる遅延があることになります。
古い未アーカイブのデータをどうするかについて制限を付けるために、archive_timeoutを設定して、強制的にサーバを新しいWALセグメントにある程度の間隔で切り替えるようにすることができます。
強制切り替えにより早期にアーカイブされたアーカイブ済みファイルは完全に完了したファイルと同じ大きさを持つことに注意してください。
そのため、非常に小さなarchive_timeout
を使用することはお勧めしません。
格納領域を膨張させてしまいます。
通常ならば分単位のarchive_timeout
設定が合理的です。
終わったばかりのトランザクションをできるだけ早くアーカイブさせたい場合、pg_switch_wal
を使用して手作業でセグメント切り替えを強制することができます。
この他のWAL管理に関連した関数を表 9.89に列挙します。
wal_level
がminimal
の場合、14.4.7に書かれているように、いくつかのSQLコマンドはWALロギングを回避するため最適化されます。
アーカイビングもしくはストリーミングレプリケーションがこれら構文の1つを実行中に作動させられると、アーカイブ復旧のための十分な情報をWALが含まなくなります。(クラッシュ復旧は影響を受けません。)
このことにより、wal_level
はサーバの起動時のみ変更可能です。
とは言っても、archive_command
とarchive_library
は構成ファイルを再読み込みすることで変更できます。
シェルでアーカイブしており、一時的にアーカイビングを停止したい場合、1つの方法はarchive_command
を空文字列(''
)に設定することです。
このようにすると、動作するarchive_command
が再構築されるまでWALファイルはpg_wal/
に蓄積します。
ベースバックアップを取得する最も簡単な方法はpg_basebackup を実行する方法です。 通常のファイルやTAR形式のファイルとしてベースバックアップを取得することができます。 もし、pg_basebackupより柔軟性が求められる場合は、低レベルなAPIを使ってバックアップを作成することもできます(詳細は 26.3.3を参照)。
ベースバックアップを取得するための時間を考慮する必要はありません。
しかし、普段、full_page_writes
を無効にして運用している場合、バックアップ取得中は強制的にfull_page_writes
が有効になるため、パフォーマンスが落ちていると感じる可能性があります。
バックアップを使用するためには、ファイルシステムのバックアップ取得中、および、その後に生成されるWALセグメントファイル全てが保存されている必要があります。
この目的のために、ベースバックアップの過程で即座にWALアーカイブ領域にバックアップ履歴ファイルが作成されます。
このファイルにはファイルシステムのバックアップに最初に必要とされるWALセグメントの名前が付けられます。
例えば、最初のWALファイルが 0000000100001234000055CD
である場合、バックアップ履歴ファイルは0000000100001234000055CD.007C9330.backup
というように名付けられます。
(ファイル名の2番目のパートはWALファイルの厳密な位置が記載されます。通常は無視することができます。)
一旦、安全にファイルシステムのバックアップとそのバックアップ中に使用されたWALセグメントファイル(バックアップ履歴ファイルから特定できます)を取得すると、それより数値の小さな全てのWALアーカイブセグメントはファイルシステムの復旧には必要が無く、削除することができます。
しかし、データを確実に復旧させるためには数世代のバックアップセットを保持することを考慮すべきです。
バックアップ履歴ファイルは、ほんの小さなテキストファイルです。 これにはpg_basebackupで与えたラベル文字列の他、バックアップの開始、終了時間およびバックアップのWALセグメントが含まれます。 このラベルをバックアップを構成するために使うことで、アーカイブ履歴ファイルはどのバックアップをリストアするべきか間違いなく判断することができます。
最後のベースバックアップ以降のWALアーカイブを保持し続ける必要があるため、通常、ベースバックアップを取得すべき期間は、WALアーカイブを保持するためにどのくらいのストレージを拡張できるかによって決定されます。 また、復旧が必要になった場合に、どのくらいの時間を復旧に使うと覚悟するのかも考慮すべきです。— システムは全てのWALセグメントを適用する必要があるため、もし、最後のベースバックアップを取得してから長い時間が経過している場合、適用に時間を要する可能性があります。
低レベルのAPIを使ったベースバックアップを取得するにはpg_basebackup を使う方法に加えて数ステップが必要ですが、比較的簡単です。 これらのステップは順番に実行することが重要で、次のステップに進む前にこれらのステップが成功していることを確認する必要があります。
複数のバックアップを同時に実行できます(このバックアップAPIを使用して開始されたバックアップとpg_basebackupを使用して開始されたバックアップの両方)。
WALアーカイブが有効であり、正常に動作することを確認してください。
pg_backup_start
の実行権限を持つユーザとしてサーバ(どのデータベースであってもかまいません)に接続します。ユーザはスーパーユーザか、またはこの関数にEXECUTE
権限を与えられたユーザです。以下のコマンドを発行します。
SELECT pg_backup_start(label => 'label', fast => false);
ここでlabel
は、このバックアップ操作を一意に識別するために使用したい文字列です。
pg_backup_start
を呼び出す接続は、バックアップが終了するまで維持されなければなりません。
さもないと、バックアップは自動的に打ち切られます。
オンラインバックアップは、常にチェックポイントの先頭から開始されます。
デフォルトでは、pg_backup_start
は、次の定期的にスケジュールされたチェックポイントが完了するまで待機します。
これには長い時間がかかる場合があります(設定パラメータcheckpoint_timeoutおよびcheckpoint_completion_targetを参照してください)。
これは、実行中のシステムへの影響を最小限に抑えるため、通常は望ましい方法です。
できるだけ早くバックアップを開始したい場合は、pg_backup_start
の2番目のパラメータとしてtrue
を渡すと、即時のチェックポイントが要求されます。
このチェックポイントは、できるだけ多くのI/Oを使用してできるだけ早く完了します。
(pg_dumpやpg_dumpallではなく)tarやcpioなどの使い慣れた任意のファイルシステムバックアップツールを使用して、バックアップを実行してください。 この作業時に、データベースの通常の操作を停止することは不要ですし、望ましい方法でもありません。 このバックアップの実行中に考慮すべき点は26.3.3.1を参照してください。
以前と同じ接続の中で、以下のコマンドを実行します。
SELECT * FROM pg_backup_stop(wait_for_archive => true);
これはバックアップモードを終了し、プライマリでは、次のWALセグメントへの自動切換えを行います。
スタンバイでは、WALセグメントを自動的に切り替えることはできません。
ですから、手動切り替えを行うためにプライマリでpg_switch_wal
を実行することをお勧めします。
この切換えの理由は、バックアップ期間中に書き出された最後のWALファイルがアーカイブできるよう準備することです。
pg_backup_stop
は3つの値を含んだ1行を返します。
2番目の値は、バックアップのルートディレクトリ内のbackup_label
という名称のファイルを作成の上、値を書き込む必要があります。
3番目の値は、空でない限りはtablespace_map
という名称のファイルを作成の上、値を書き込む必要があります。
これらのファイルはバックアップが動作するために極めて重要であり、1バイトも変更なしに書き込まれる必要があるため、バイナリモードで開かれる必要があるかもしれません。
バックアップ中に使用されたWALセグメントファイルがアーカイブされれば完了です。
pg_backup_stop
の返り値の1番目の値で識別されるファイルは、バックアップファイル一式を完結させるのに必要となる最終セグメントです。
プライマリでは、archive_mode
が有効で、かつwait_for_archive
パラメータがtrue
であれば、pg_backup_stop
は最終セグメントがアーカイブされるまで戻りません。
スタンバイでは、pg_backup_stop
がアーカイブ完了を待つためには、archive_mode
はalways
でなければなりません。
すでにarchive_command
あるいはarchive_library
を設定していますので、これらのファイルのアーカイブ操作は自動的に発生します。
ほとんどの場合、これは瞬時に行われます。
しかし、バックアップの完了を確認できるよう、アーカイブシステムを監視し、遅延が無いことの確認をお勧めします。
アーカイブコマンドの失敗によりアーカイブ処理が遅れてしまったとしても、アーカイブが成功し、そしてバックアップが完了するまで再試行を繰り返すようになっています。
pg_backup_stop
実行においての時間期限を設けたい場合、適切なstatement_timeout
の値を設定できますが、この設定値によってpg_backup_stop
が中断したときにバックアップが正当ではない可能性があるということを肝に銘じてください。
バックアップに必要なすべてのWALセグメントファイルのアーカイブが成功したことを、バックアップ作業の中で監視して確認するのであれば、wait_for_archive
パラメータ(デフォルトでtrueです)をfalseに設定し、バックアップレコードがWALに書き込まれたら即座にpg_backup_stop
が戻るようにすることができます。
デフォルトでは、pg_backup_stop
はすべてのWALがアーカイブされるのを待つので、少し時間がかかることがあります。
このオプションは慎重に使わなければなりません。
WALのアーカイブを適切に監視していない場合、バックアップにはすべてのWALファイルが含まれず、不完全かもしれません。
そうなると、リストアできません。
ファイルシステムのバックアップツール中には複写している途中でファイルが変更されると警告もしくはエラーを報告するものがあります。
稼働しているデータベースのベースバックアップを取っている場合には、この状況は正常でエラーではありません。
しかし、この種の警告と本当のエラーとを区別できるか確認が必要です。
例えば、rsyncのバージョンによっては「消滅したソースファイル」に対して別の終了コードを返し、そしてこの終了コードをエラーではないと受け付けるドライバスクリプトを記述することができます。
同時にGNU tarのバージョンによっては、tarがそれを複写していた途中でファイルが切り詰められると、致命的エラーと識別できないエラーコードを返します。
ありがたいことに、GNU tarのバージョン1.16もしくはそれ以降では、バックアップ中にファイルが変更されると1で、それ以外のエラーの時は2でプログラムから抜けます。
GNUの tarで1.23以降のバージョンを使用しているのであれば、--warning=no-file-changed --warning=no-file-removed
オプションをつけることで関連する警告メッセージを隠すオプションを使用することができます。
バックアップに、データベースクラスタディレクトリ(例えば/usr/local/pgsql/data
)以下にある全てのファイルが含まれていることを確認してください。
このディレクトリ以下に存在しないテーブル空間を使用している場合、注意して、同様にそれらを含めてください
(そして、バックアップがリンクとしてシンボリックリンクをアーカイブしていることを確認してください。
さもないとリストアはテーブル空間を壊してしまいます)。
しかし、クラスタのpg_wal/
サブディレクトリにあるファイルをバックアップから省いてください。
このちょっとした調整は、リストア処理中の失敗の危険性を低減できますので、行う価値があります。
pg_wal/
がクラスタディレクトリ外のどこかを指し示すシンボリックリンクの場合は調整が簡単です。
これは性能上の理由でよく使用される設定です。
また、いずれこのバックアップを使うpostmasterではなく、今起動しているpostmasterの情報を記録しているpostmaster.pid
とpostmaster.opts
も除外できます。
(これらのファイルはpg_ctlを誤作動させる可能性があります。)
プライマリ上に存在するレプリケーションスロットがバックアップに含まれないようにするために、クラスタの中のpg_replslot/
ディレクトリをバックアップから除くのもしばしば良い考えです。
もし、スタンバイを作成するためのバックアップを続けて使用すると、スタンバイのWALファイルの保持を無制限に保留する結果になり、ホットスタンバイからのフィードバックを有効にしている場合、プライマリのWALを膨張させます。
これは、これらのレプリケーションスロットを使っているクライアントはまだ、スタンバイではなく、プライマリのスロットを接続し続け、更新しているからです。
バックアップが新しいプライマリを作成するためだけに作成されたとしても、レプリケーションスロットをコピーすることは特に有益であるとは考えられません。
このようにバックアップにレプリケーションスロットを含むことは、新しいプライマリがオンラインになったときにはスロットの内容が期限切れしており、有害である可能性があります。
ディレクトリpg_dynshmem/
、pg_notify/
、pg_serial/
、pg_snapshots/
、pg_stat_tmp/
、pg_subtrans/
の中身はバックアップから除外できます。(ただし、ディレクトリ自体は除外できません。)
というのも、postmaster起動時に初期化されるからです。
pgsql_tmp
で始まるすべてのファイルとディレクトリはバックアップから除外できます。
これらのファイルはpostmasterの起動時に削除されますし、ディレクトリも必要なら再作成されます。
pg_internal.init
という名前のファイルが見つかった場合、それはバックアップから省くことができます。
このファイルはリレーションキャッシュデータを含んでおり、常にリカバリの際に再構築されます。
バックアップラベルファイルには、pg_backup_start
に付与したラベル文字列とpg_backup_start
が実行された時刻、最初のWALファイルの名前が含まれます。
したがって、当惑した時にバックアップファイルの中身を検索し、そのダンプファイルがどのバックアップセッションに由来したものかを確認することができます。
テーブル空間マップファイルにはディレクトリpg_tblspc/
に存在するシンボリックリンク名と各シンボリックリンクのフルパスが含まれています。
このファイルはあなたのためだけの情報ではありません。
その存在と内容はシステムのリカバリプロセスが適切に動作するために非常に重要です。
サーバが停止している時にバックアップを作成することも可能です。
この場合、わかりきったことですが、pg_backup_start
やpg_backup_stop
を使用することができません。
そのため、どのバックアップが、どのWALファイルと関連し、どこまで戻せばよいかを独自の方法で残さなければなりません。
通常は、上述の継続的アーカイブ手順に従う方をお勧めします。
さて、最悪の事態が発生し、バックアップから復旧する必要が出てきたものとします。 以下にその手順を説明します。
もし稼働しているのであればサーバを停止してください。
もし容量があるのであれば、後で必要になる場合に備えてクラスタデータディレクトリ全体とテーブル空間を全て一時的な場所にコピーしてください。
この予防措置は、既存のデータベースを2つ分保持できるだけの空き領域を必要とします。
十分な領域がない場合でも、少なくともクラスタのpg_wal
サブディレクトリの内容は保存すべきです。
ここには、システムが停止する前にアーカイブされなかったログファイルが含まれているかも知れないからです。
クラスタデータディレクトリ以下、および、使用中のテーブル空間の最上位ディレクトリ以下にある既存の全てのファイルとサブディレクトリを削除してください。
ファイルシステムバックアップからデータベースファイルをリストアします。
ファイルが正しい所有権(root
ではなくデータベースシステムユーザです!)でリストアされていることを確認してください。
テーブル空間を使用している場合は、pg_tblspc/
内のシンボリックリンクが正しくリストアされていることを検証する必要があります。
pg_wal/
内にあるファイルをすべて削除してください。
これらはファイルシステムバックアップから生成されたものであり、おそらく現在のものより古く使用できないものです。
pg_wal/
をまったくアーカイブしていなければ、適切な権限で再作成してください。
以前シンボリックリンクとして設定していたのであれば、そのように確実に再構築するように注意してください。
手順2で退避させた未アーカイブのWALセグメントファイルがあるのであれば、pg_wal/
にコピーしてください。
(問題が発生し、初めからやり直さなければならない場合に未変更のファイルが残るように、移動させるのではなくコピーすることが最善です。)
postgresql.conf
(20.5.5を参照してください)に復旧の設定を記述し、クラスタデータディレクトリにrecovery.signal
ファイルを作成します。
また、一時的にpg_hba.conf
を変更し、復旧の成功を確認できるまで一般ユーザが接続できないようにする必要があるかもしれません。
サーバを起動してください。
サーバは復旧モードに入り、必要なアーカイブ済みWALファイル群の読み込みを行います。
外部的なエラーにより復旧が中断したら、サーバを単に再起動させて、復旧処理を継続してください。
復旧処理が完了したら、(誤って後で復旧モードに再度入らないように)サーバはrecovery.signal
を削除します。
その後通常のデータベース操作を開始します。
データベースの内容を検査し、希望する状態まで復旧できていることを確認してください。
復旧できなかった場合は手順1に戻ってください。
全て問題なければ、ユーザが接続できるようにpg_hba.conf
を正常状態に戻してください。
ここで重要となるのは、どのように復旧させたいのかやどこまで復旧させたいかを記述する復旧設定を設定することです。
絶対に指定しなければならないことは、アーカイブ済みWALファイルセグメントをどのように戻すかをPostgreSQLに通知するrestore_command
です。
archive_command
同様、これはシェルコマンド文字列です。
ここには、対象のログファイルの名前で置換される%f
やログファイルのコピー先を示すパスで置換される%p
を含めることができます。
(パス名は現在の作業用ディレクトリ、つまり、クラスタのデータディレクトリから見た相対パスです。)
コマンド内に%
文字自体を埋め込む必要があれば%%
と記載してください。
最も簡単でよく使われるコマンドは以下のようなものです。
restore_command = 'cp /mnt/server/archivedir/%f %p'
これは事前にアーカイブされたWALセグメントを/mnt/server/archivedir
ディレクトリからコピーします。
当然ながら、もっと複雑なものを使用することができます。
例えば、操作者に適切なテープをマウントさせることを要求するようなシェルスクリプトでさえ可能です。
このコマンドが失敗した時に非ゼロの終了ステータスを返すことが重要です。 このコマンドは、アーカイブに存在しないファイルを要求するかもしれませんが、その場合でも非ゼロを返さなければなりません。 これはエラー状態ではありません。 例外は、コマンドがシグナルによって中断された場合(データベースの停止に使用されるSIGTERM以外)か、シェルによるエラー(コマンドが見つかりませんなど)で復旧が中断され、サーバが起動しない場合です。
要求されるファイルはWALセグメントファイルだけではありません。
.history
が付いているファイルが要求されることも想定しなければなりません。
同時に、%p
パスのファイル名部分は%f
と異なることに注意してください。
これらが相互に置き換え可能であるとは考えないでください。
アーカイブ場所で見つけられなかったWALセグメントはpg_wal/
から検索されます。
これにより、最近の未アーカイブのセグメントを使用することができます。
しかし、アーカイブ場所から利用できるセグメントはpg_wal/
内のファイルよりも優先的に使用されます。
通常は利用可能な全てのWALセグメントを使用して復旧処理が行われます。
その結果、データベースを現時点まで(もしくは、利用可能なWALセグメントで得られる限り現在に近い時点まで)リストアします。
従って、通常の復旧は「file not found」メッセージで終了します。
エラーメッセージの正確な文言はrestore_command
の選択によります。
また、復旧の開始時点で00000001.history
のようなファイル名のエラーメッセージが出ることがあります。
これも単純な復旧作業では不具合を意味するものでなく正常です。
論議については26.3.5を参照してください。
もし以前のある時点まで復旧させたい場合(例えば、経験不足のデータベース管理者が主トランザクションテーブルを消去した直前)、要求する停止時点を指定するだけです。 停止時点は、「recovery target」として既知の停止時点で指定することも、日付と時刻で指定することも、リストアポイントか完了した特定のトランザクションIDで指定することもできます。 本ドキュメントの執筆時点では使用するトランザクションIDの識別を補助するツールがありませんので、ほとんどの場合は日付と時刻による指定のみを使用することになるでしょう。
停止時点はバックアップの終了時刻、つまり、pg_backup_stop
の最終時刻より後の時点でなければなりません。
バックアップを行っている最中のある時点までベースバックアップを使用して復旧させることはできません
(こうした時点まで復旧させるには、その前のベースバックアップまで戻って、そこからロールフォワードしてください)。
復旧時にWALデータの破損がわかると、復旧はその時点で止まり、サーバは起動しません。
こうした場合、「復旧対象」に破損時点より前の時点を指定することで、復旧処理が正常に完了できるよう、復旧プロセスを初めからやり直すことができます。
システムクラッシュなど外的理由により復旧処理が失敗した場合やWALアーカイブがアクセスできなくなった場合、復旧処理を単に再起動させることができます。
この場合は失敗した時点とほぼ同じところから再開します。
復旧処理の再起動は、次のような通常操作時のチェックポイント処理とほぼ同様に動作します。
サーバは定期的にすべての状態をディスクに強制し、再度スキャンする必要がない処理済みのWALデータを示すpg_control
ファイルを更新します。
過去のある時点までデータベースを復旧できる機能は、タイムトラベルやパラレルユニバースといったSFの物語に類似した、多少の複雑性があります。 例えば、データベースの元の履歴で、火曜日の夕方5:15PMに重要なテーブルを削除し、水曜日のお昼まで手違いに気が付かなかったとします。 慌てずに、バックアップを取り出して、火曜日の夕方5:14PMの時点にリストアし、データベースを起動させます。 データベース世界のこの履歴では、そのテーブルを削除していません。 しかし、後になって、これは大した問題ではなかったことが分かり、元の履歴における水曜日に朝の何時かにまで戻したいと考えたと仮定しましょう。 データベースは既に起動していますので、元に戻したい時点に至るWALセグメントファイルの一部は上書きされていて、戻すことはできないかもしれません。 ですので、このことを避けるために、ポイントインタイムで復旧させた後に生成された一連のWAL記録と元のデータベースの履歴において生成されたWAL記録とを区別する必要があります。
こうした問題を扱うためにPostgreSQLにはタイムラインという概念があります。 アーカイブ復旧が完了したときはいつでも、その復旧後に生成されたWAL記録を識別するための新しいタイムラインが生成されます。 タイムラインID番号はWALセグメントファイル名の一部です。 ですので、新しいタイムラインはこれまでのタイムラインで生成されたWALデータを上書きしません。 実際、多くの異なるタイムラインをアーカイブすることができます。 不要な機能と考えるかもしれませんが、命綱になることがしばしばあります。 どの時点まで復旧すればよいか確実でないといった状況を考えてみてください。 その時は、過去の履歴からの分岐点として最善の時点を見つけるために、試行錯誤して何度もポイントインタイムの復旧を行う必要があるでしょう。 タイムラインがないと、この手続きはすぐに管理不能な混乱を招いてしまいます。 タイムラインを使用して、以前捨てたタイムライン分岐における状態を含む、過去の任意の状態に復旧させることができます。
新しいタイムラインが生成される度に、PostgreSQLは、どのタイムラインがいつどこから分岐したかを示す「タイムライン履歴」ファイルを作成します。 この履歴ファイルは、複数のタイムラインを含むアーカイブ場所から復旧する時にシステムが正しいWALセグメントファイルを選択できるようにするために必要です。 したがって、履歴ファイルは、WALセグメントファイル同様にWALアーカイブ領域にアーカイブされます。 履歴ファイルは(巨大になるセグメントファイルとは異なり)単なる小さなテキストファイルですので、安価かつ適切に無期限で保管できます。 必要ならば、履歴ファイルにコメントを追加し、この特定のタイムラインがどのように、なぜ生成されたかについて独自の注釈を付与することができます。 特にこうしたコメントは、実験の結果いくつものタイムラインのもつれがある場合に有用です。
復旧処理のデフォルトは、アーカイブで見つかった最新のタイムラインへの復旧です。
ベースバックアップが取得された時点のタイムラインと同一のタイムラインや別の子タイムラインに沿って復旧させたい(つまり、復旧試行以降に生成されたある状態に戻りたい)場合は、current
かrecovery_target_timelineで対象のタイムラインIDを指定しなければなりません。
ベースバックアップより前に分岐したタイムラインに沿って復旧することはできません。
継続的アーカイブを構成するいくつかのヒントを以下にあげます。
スタンドアローンホットバックアップを形成するためPostgreSQLのバックアップ基盤を使用することができます。 これらのバックアップはポイントインタイムリカバリに使用することはできないのですが、pg_dumpによるダンプよりバックアップとリストアが概してより速く行われます。 (同時にpg_dumpのダンプより大きくなるので、場合によっては速度による利点が打ち消されるかもしれません。)
ベースバックアップと同様に、スタンドアローンホットバックアップを作成する最も簡単な方法は pg_basebackupツールを使用する方法です。
実行時に-X
オプションをつけることでバックアップに必要な全ての先行書き込みログを自動的にバックアップに含めることができ、リストアするときには特に特別な作業を行う必要がありません。
もし、アーカイブのストレージ容量に懸念がある場合、アーカイブファイルを圧縮するためにgzipを使用することもできます。
archive_command = 'gzip < %p > /mnt/server/archivedir/%f.gz'
復旧時は gunzipを使う必要があります。
restore_command = 'gunzip < /mnt/server/archivedir/%f.gz > %p'
archive_command
スクリプト
postgresql.conf
の記入事項が以下のように簡素となるため、多くの人がarchive_command
の定義にスクリプトの使用を選択します。
archive_command = 'local_backup_script.sh "%p" "%f"'
アーカイブ処理手順において単一ではなくそれ以上の数のコマンドを使用したい場合はいつでも、別のスクリプトファイルの使用が推奨されます。 そうするとスクリプト内で全ての複雑性が管理されます。 スクリプトはbashまたはperlのようなよくあるスクリプト言語で記載できます。
スクリプト内で解決される要件の例として以下があります。
セキュアなオフサイトデータストレージへのデータのコピー
一回に全てではなく3時間毎に転送されるようにWALファイルのバッチ
その他のバックアップとリカバリのソフトウェアとのインタフェース
エラー報告を行う監視ソフトとのインタフェース
archive_command
スクリプトを使うときはlogging_collectorを使えるようにすることが望ましい方法です。
そのスクリプトがstderrに書き出したメッセージはすべて、データベースのサーバーログとして書かれます。
このため複雑な設定でエラーが発生した時に、簡単に原因を突き止められます。
本ドキュメント作成時点では、継続的アーカイブ技術にいくつかの制限があります。 将来のリリースでは修正されるはずです。
もしもベースバックアップが行われている時、CREATE DATABASE
コマンドが実行され、ベースバックアップが処理を実行している期間にCREATE DATABASE
がコピーしているtemplateデータベースが変更されると、復旧処理はこれらの変更を作成されたデータベースにも同時に伝播させることは確実です。
もちろん、これは望まれる事ではありません。
この危険を回避するには、ベースバックアップ期間中にはすべてのtemplateデータベースを変更しないことが一番です。
CREATE TABLESPACE
コマンドはリテラルの絶対パス付でWALにログが記録され、したがって、同じ絶対パスでのテーブル空間作成の時に再生されます。
これは、もしログが異なったマシン上で再生される場合には好ましくありません。
ログ再生がたとえ同一のマシンであっても、新規のデータディレクトリであれば危険です。
なぜなら、再生は元のテーブル空間の内容を上書きし続けるからです。
この種の潜在的な振舞いを防ぐためには、テーブル空間を作成もしくは削除後に新規ベースバックアップを行うのが最良の手段です。
また、デフォルトのWALフォーマットは数多くのディスクページのスナップショットを含んでいるため、かなりかさばるものになってしまっていることに触れておくべきでしょう。
これらのページスナップショットは、クラッシュから回復のために設計されています。
それというのも、回復処理の際には不完全に書き込まれているディスクページを修復しなければならないことがあるからです。
システムのハードウェアやソフトウェアによっては、不完全なディスクページの書き込みが起きてしまう危険性は無視してもよい程微小です。
この場合full_page_writesパラメータを設定してページスナップショットを無効にすることで、アーカイブされたログの総容量を大幅に縮小できます
(実際に設定を行う前に、第30章の注意事項と警告を読んでください)。
ページスナップショットを無効にしても PITR処理の際にログが使用できなくなることはありません。
将来の課題は、full_page_writes
がたとえオンになっている場合であっても不要なページを取り除き、アーカイブ済みWALデータの圧縮を行うことでしょう。
差し当たり管理者は、可能な限りチェックポイント間隔パラメータを大きくすることによって、WALに含まれるページスナップショットの数を削減することができます。