物理バップアップの概要

物理バップアップの概要

NTT オープンソースソフトウェアセンタ 鈴木 幸市

 

4. 物理バックアップ

前記事では pg_dump や pg_dumpall を用いた論理バックアップを紹介しました。本章では物理バックアップについて解説していきます。

pg_dump などを利用した論理バックアップでは、特定のデータベースやテーブル、あるいはスキーマなどを個別にバックアップできました。 一方、物理バックアップはデータベース・クラスタ全体の粒度でのみバックアップできます。 物理バックアップには、オフライン・バックアップとオンライン・バックアップがあります。 本章ではこれらについて解説します。

5. オフライン・バックアップとリストア

オフライン・バックアップは、PostgreSQLの運転を停止させ、データベースの内容をまるごとそのままバックアップするものです。

操作は単純で、バックアップは tar や rsync などのOSのファイルバックアップコマンドやツールを使用します。 データベースのデータは、環境変数 PGDATA に指定されているディレクトリ配下、及びテーブルスペースで使用しているディレクトリ配下にあります。 これらのデータをすべてバックアップすることになります。

まずはPostgreSQLを停止します。その後、PostgreSQLが動作していないことを確認します。 下記は"/usr/local/pgsql/data"にデータベース・クラスタがある場合です。

$ pg_ctl -D ~/usr/local/pgsql/data stop
waiting for server to shut down.... done
server stopped
$ pg_ctl status
pg_ctl: no server running

次に、データベース・クラスタの全データをバックアップします。 バックアップ先は"~/tmp"としています。

$ tar czf ~/tmp/db.tar.gz -C / /usr/local/pgsql/data
tar: メンバ名から先頭の `/' を取り除きます

テーブルスペースを使用している場合には、割り当てているディレクトリも忘れずにバックアップをします。 PostgreSQL のテーブルスペースは、ディレクトリへのシンボリックリンク (Windows ではジャンクション) を利用しているため、リンク先のデータも保存する必要があります。 下記は"/other/pgsql/ts"ディレクトリをテーブルスペースで使用している場合です。 バックアップ先はデータベース・クラスタと同じです。

$ tar czf ~/tmp/ts.tar.gz -C / /other/pgsql/ts
tar: メンバ名から先頭の `/' を取り除きます

これでバックアップ作業は完了です。

リストアは非常に簡単です。 バックアップしたデータベースクラスタやテーブルスペースを元に戻してPostgreSQLを起動すれば完了です。 この例では、データベースクラスタとテーブルスペースのディレクトリを削除してからリストアしています。

$ rm -rf /usr/local/pgsql/data
$ rm -rf /other/pgsql/ts
$ tar xzf ~/tmp/db.tar.gz -C /
$ tar xzf ~/tmp/ts.tar.gz -C /
$ pg_ctl start
server starting

オフライン・バックアップは大変簡単ですが、データベース・サーバを停止させる必要があるため、サービスが止まってしまいます。 また、リストアの際にはデータベースの状態がバックアップの時点に戻ってしまいます。 バックアップの取得後にデータベースに加えられた変更は失われます。 もし最新の変更まで復元したい場合には、次に説明するオンライン・バックアップを代わりに使用します。

6 オンライン・バックアップについて

オンライン・バックアップは、オフライン・バックアップよりも手順は複雑になりますが、データベースを運転したままバックアップでき、かつバックアップ後に行った更新結果も復元することができます。 オンライン・バックアップはPostgreSQL 8.0以降で利用できます。

オンライン・バックアップでは、データベースを最新の状態にするだけでなく、任意の時刻の状態に戻すPITR (Point In Time Recovery)も導入されています。これについては次回解説したいと思います。今回は、バックアップの取得方法まで解説します。

オフライン・バックアップと異なり、PostgreSQLを稼動したままバックアップを行います。 バックアップ自体に使用するのは、オンライン・バックアップでも同様に、汎用のファイルコピーを行うツールを用いてデータベースの全データをバックアップします。 ただ、バックアップ中にファイルが作成、削除、変更される可能性があるため、これらに対応できるツールが必要です。 一般的によく使われるのは rsync です。 一見 tar も利用できそうですが、上記のようなファイル構成の変更があるため、バックアップの成功 or 失敗を判断しづらくなる問題があります。

この際に取得するバックアップを特にベースバックアップと呼びます。 ベースバックアップを取得している間もデータベースは更新されますので、そのままでは整合性の保たれていないファイル群をバックアップすることになります。ベースバックアップ取得中の更新情報はWAL (Write-Ahead Log)に記録されており、これを使ってベースバックアップを整合性の保たれた状態へ戻すことができます。つまり、ベースバックアップとベースバックアップ取得中のWALを保存しておけば、リストアが可能になるわけです。

6.1 オンライン・バックアップの取得準備

WALは元来チェックポイント間でデータベースがクラッシュしたときに自動リカバリを行うために作られているものですので、何もしないと不要になったWALは捨てられてしまいます。 これではオンライン・バックアップのリストアに支障があります。そこで、WALが捨てられる際にこれを別な場所に保存する機能がPostgreSQLにはあります。 これがアーカイブログです。

オンライン・バックアップを取るには、まずWALをアーカイブログとして保存できるようにする必要があります。

これは、PostgreSQLの設定ファイルである postgresql.conf ファイルで指定します。 そのエントリは次の2つです。

1) archive_mode

archive_modeは、PostgreSQLのver8.3以降に付与されたパラメータです。デフォルトではOFFになっています。これをONにします。(ver8.2以前では特にすることはありません)

2) archive_command

archive_commandは、デフォルトでは空の文字列です。ここにWALを他のディレクトリ等にコピーするコマンドを指定します。 archive_mode がONになっていると、WALが捨てられる度にこのコマンドを呼び出し、 WALセグメント(WALを格納するファイル)を他の場所にバックアップしておくことができるようになっています。

archive_command の指定例は次の通りです。

archive_command = 'cp %p /var/postgresql/archivedir/%f

ここで、%pはバックアップすべきWALセグメントのパス名で、%fはそのファイル名をそれぞれ置換するものです。

postgresql.conf の設定を変更して再起動すれば、上記のアーカイブ取得が開始されます。

これでオンライン・バックアップを取得する準備ができました。

6.2 オンライン・バックアップの取得

オンライン・バックアップは、オフラインバックの取得時とは違い、若干バックアップ方法が煩雑になります。では手順を追って見ていきましょう。

1. pg_start_backup()の発行

本節の冒頭で述べたとおり、オンライン・バックアップで取得したベースバックアップには、取得中に発生したWALも必要になります。どこからどこまでのWALが必要になるのかを、PostgreSQLに教える関数を発行する必要があります。

これを行うのが、pg_start_backup() 及び pg_stop_backup() 関数です。それぞれ、ベースバックアップの取得前後に発行することになります。ベースバックアップの取得前に発行するpg_start_backup() 関数には、バックアップを示すラベルを指定します。ラベルはユーザの任意で自由に記述できます。典型的には、"いつ"バックアップが開始されたかを示す時間を打つと良いでしょう。

まず pg_start_backup() 関数を呼び出します。下記の例では、now()で現在時刻を呼び出し、それをtext型にキャストしています。(pg_start_backup()は本来text型のデータを引数に持つからです)

$ psql -c "SELECT pg_start_backup(now()::text)"
 pg_start_backup
-----------------
 0/5000020
(1 row)

なお、pg_start_backup()の裏ではチェックポイントが実行されます。PostgreSQLのver8.3で負荷分散チェックポイントが導入されたため、pg_start_backup()を発行してもなかなか終了しないことがあります。もし、pg_start_backup()中に一時的に高めのI/Oが発生しても構わないようであれば、pg_start_backup()関数の第2引数に'true'をセットしましょう。I/O負荷とトレードオフで、チェックポイント時間を短くできます(PostgreSQLのver8.4以降で有効な機能)。

2. ベースバックアップの取得

次いで、PostgreSQLのベースバックアップを取得します。この際、pg_xlogディレクトリとpostmsater.pidをバックアップ対象から除いておくと、リストア時の手順が簡略化でき、ベースバックアップのサイズ削減にもなります。また、オフラインバックの時と同様に、テーブルスペースで割り当てているディレクトリも忘れずバックアップしましょう。下記は、データベース・クラスタのみのバックアップをしている例です。

$ rsync -av --delete --exclude=pg_xlog --exclude=postmaster.pid \
/usr/local/pgsql/data/* ~/tmp/backup/data
↑実際には一行です。

オンライン・バックアップ時には、rsyncの使用を推奨します。ベースバックアップの取得時にはPostgreSQLによるファイル操作が実施されているため、tarなどのコマンドから見るとバックアップすべきファイルが途中で消失したように見えます。これは本来起こっても良い現象なのですが、古いtar(1.16より前)などのエラー返却値では無視してよいかどうかを判別できません。一方、rsyncではエラーの種別により細かく返却値が定められており、code:24は許容できるエラーとして扱えます。そのため、ベースバックアップの取得にはrsyncを使い、返却値"24"を無視すると良いです。

3. pg_stop_backup()の発行

最後に、pg_stop_backup() 関数を呼び出します。引数は必要ありません。 この関数では特に重い処理は行われないため、短時間で終わるでしょう。

$ psql -c "SELECT pg_stop_backup()"
 pg_stop_backup
----------------
 0/5000088
(1 row)

これでバックアップは完了です。上記の手順の間、PostgreSQLは稼動したままで、様々な処理も受け付けている状態です。

それでは、次回はオンライン・バックアップで取得したベースバックアップとアーカイブログを使ったPITRについて、その方法を紹介します。


(2010年4月30日 公開)