PostgreSQL 9.0でPITR(Point In Time Recovery)を実行
目次
概要
PostgreSQL 9.0でPITR(Point In Time Recovery)を実行します。
あえてバージョンを明記しているのは、9.1以降では実行するコマンドが少し変わるためです。
以下の流れでバックアップとリカバリを実行します。
(1) PITRのためのベースバックアップの取得
(2) データの更新
※このタイミングでデータファイルが破損した想定
(3) PostgreSQLインスタンスの停止
(4) ベースバックアップの復元
(5) 最新のWALログの復元
(6) リカバリ設定ファイルの作成
(7) PostgreSQLインスタンスの起動
構成
想定環境
本バックアップ・リカバリ手順では下記ディレクトリ・ファイル構成であることを前提に説明します。
データベースクラスタ($PGDATA) | /data/pgdata1/ |
---|---|
WALディレクトリ | /data/pgdata1/pg_xlog/ |
WALアーカイブディレクトリ | /bkup/pgdata1/pg_arch/ |
PostgreSQLログ | /data/pgdata1/pg_log/ |
バックアップラベル | 20131218_Backup |
ベースバックアップファイル | /bkup/20131218_pgdata1.tar.gz |
リカバリ設定ファイル | /data/pgdata1/recovery.conf |
サーバ構成
OSバージョン
Red Hat Enterprise Linux 5.9 x86_64
ソフトウェア・パッケージ一覧
postgresql90-9.0.8-1PGDG.rhel6.x86_64.rpm
postgresql90-libs-9.0.8-1PGDG.rhel6.x86_64.rpm
postgresql90-server-9.0.8-1PGDG.rhel6.x86_64.rpm
手順
バックアップ
PITRのためのベースバックアップ取得
まず始めにデータベースクラスタをリストアする際のベースとなるバックアップを取得します。 ベースバックアップは任意の時点でのデータベースクラスタの静止点です。 このベースバックアップに対してWAL(データベースの更新情報)を適用してデータベースを 復旧していくことになります。
ベースバックアップはPostgreSQLインスタンスが起動した状態で取得します。 そのため、バックアップ中にデータベースファイル(ディスク)に対して更新が されないような仕組みが導入されています。
psqlでpg_start_backup()関数を実行すると、内部的にcheckpointが実行されます。 これによりその時点でのバッファ(メモリ)上の更新情報がディスクに反映されます。 また、それ以降の更新情報はディスクに反映されなくなります。 これでデータベースの静止点が取れます。
pg_start_backup()の引数にはラベルを指定します。 ラベルには何を指定しても良いのですが、ベースバックアップ取得時の 日付や日時などを指定するのが一般的なようです。 このラベルは特に覚えておく必要はありません。
-bash-3.2$ psql -c "select pg_start_backup('20131218_Backup')" pg_start_backup ----------------- 0/1D000020 (1 行)
続いてデータベースクラスタのバックアップを取得します。 バックアップにはOSコマンドを使用します。 cpやtarコマンドで別の同じサーバのディスクにコピーしても良いですし、 scpやrsyncコマンドなどで別のサーバにコピーしても良いです。 ここではPostgreSQLインスタンスが起動しているのと同じサーバ上の 別のディスクに対してtarコマンドでバックアップします。 バックアップ対象はデータベースクラスタ全体($PGDATA環境変数に設定してあるディレクトリ)です、
-bash-3.2$ cd /data/
-bash-3.2$ tar zcvf /bkup/20131218_pgdata1.tar.gz ./pgdata1
./pgdata1/
./pgdata1/postmaster.opts
./pgdata1/pg_hba.conf
./pgdata1/pg_notify/
./pgdata1/pg_notify/0000
(中略)
./pgdata1/pg_multixact/members/0000
./pgdata1/pg_multixact/offsets/
./pgdata1/pg_multixact/offsets/0000
./pgdata1/pg_clog/
./pgdata1/pg_clog/0000
-bash-3.2$ ls -l /bkup/20131218_pgdata1.tar.gz
-rw-r--r-- 1 postgres postgres 2819055 12月 18 02:47 /bkup/20131218_pgdata1.tar.gz
OSコマンド(上の例ではtar)でのデータベースクラスタのコピーが終了したら、 ベースバックアップ取得完了をPostgreSQLへ伝える必要があります。 psqlでpg_stop_backup()関数を実行します。 引数は不要です。 するとベースバックアップ取得中に停止されていたデータベースの更新をディスクへ反映する 処理が開始され、通常の状態に戻ります。
-bash-3.2$ psql -c "select pg_stop_backup()" NOTICE: pg_stop_backup complete, all required WAL segments have been archived pg_stop_backup ---------------- 0/1D0000D8 (1 行) -bash-3.2$
データの更新
ベースバックアップ取得後にデータベースに対して追加、更新、削除などが実行されるかと思います。 その後、操作ミスなどによりデータベースファイルを誤って消してしまったことを想定します。
リカバリ
PostgreSQLインスタンスの停止
データベースクラスタの復旧を行うに当たり、まずはPostgreSQLインスタンスを停止します。 (データベースファイルが消失した場合、PostgreSQLインスタンスはダウンしてしまうかもしれませんが。。。) 正常に停止しない場合はOSのkillコマンドでSIGKILLシグナルを投げて、強制的に停止させてください。
-bash-3.2$ pg_ctl stop -m fast サーバ停止処理の完了を待っています....完了 サーバは停止しました -bash-3.2$ ps -ef | grep postgres avahi 3201 1 0 Dec17 ? 00:00:00 avahi-daemon: running [postgresql.local] root 6823 6555 0 19:59 pts/1 00:00:00 su - postgres postgres 6824 6823 0 19:59 pts/1 00:00:00 -bash postgres 6868 6824 0 19:59 pts/1 00:00:00 ps -ef postgres 6869 6824 0 19:59 pts/1 00:00:00 grep postgres -bash-3.2$
ベースバックアップの復元
PostgreSQLインスタンスが停止したら、バックアップしておいたベースバックアップ (今回の例ではデータベースクラスタのtarファイル)を復元します。 その際に、破損してしまったデータベースクラスタのディレクトリは消さずにとっておきます。 全てとっておく必要はないのですが、ディスクの空き容量に余裕があれば念のため全てとっておきます。
-bash-3.2$ cd $PGDATA/.. -bash-3.2$ ls -l 合計 16 drwx------ 13 postgres postgres 4096 12月 18 02:48 pgdata1 -bash-3.2$ mv pgdata1 pgdata1.bk20131218 -bash-3.2$ ls -l 合計 12 drwx------ 14 postgres postgres 4096 12月 18 20:00 pgdata1.bk20131218
ベースバックアップのtarファイルをデータベースクラスタのパスに復元します。
-bash-3.2$ tar zxvf /bkup/20131218_pgdata1.tar.gz ./pgdata1/ ./pgdata1/postmaster.opts ./pgdata1/pg_hba.conf ./pgdata1/pg_notify/ ./pgdata1/pg_notify/0000 (中略) ./pgdata1/pg_multixact/members/0000 ./pgdata1/pg_multixact/offsets/ ./pgdata1/pg_multixact/offsets/0000 ./pgdata1/pg_clog/ ./pgdata1/pg_clog/0000 -bash-3.2$ ls -l 合計 12 drwx------ 13 postgres postgres 4096 12月 18 02:47 pgdata1 ←ベースバックアップの復元 drwx------ 14 postgres postgres 4096 12月 18 20:00 pgdata1.bk20131218 -bash-3.2$
最新のWALログの復元
ベースバックアップを復元すると、WALもベースバックアップを取得した時の状態に戻ってしまいます。 データベースを最新の状態に復旧するためには、最新のWALが必要となりますので、 退避しておいた破損したデータベースクラスタのディレクトリ内から、最新のWALを復元します。
-bash-3.2$ rm -rf $PGDATA/pg_xlog -bash-3.2$ cp -pivr $PGDATA/../pgdata1.bk20131218/pg_xlog $PGDATA/ `/data/pgdata1/../pgdata1.bk20131218/pg_xlog' -> `/data/pgdata1/pg_xlog' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/000000010000000000000022' -> `/data/pgdata1/pg_xlog/000000010000000000000022' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/000000010000000000000020' -> `/data/pgdata1/pg_xlog/000000010000000000000020' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/00000001000000000000001F' -> `/data/pgdata1/pg_xlog/00000001000000000000001F' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/000000010000000000000023' -> `/data/pgdata1/pg_xlog/000000010000000000000023' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/00000001000000000000001E' -> `/data/pgdata1/pg_xlog/00000001000000000000001E' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/archive_status' -> `/data/pgdata1/pg_xlog/archive_status' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/archive_status/00000001000000000000001E.done' -> `/data/pgdata1/pg_xlog/archive_status/00000001000000000000001E.done' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/archive_status/00000001000000000000001D.00000020.backup.done' -> `/data/pgdata1/pg_xlog/archive_status/00000001000000000000001D.00000020.backup.done' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/00000001000000000000001D.00000020.backup' -> `/data/pgdata1/pg_xlog/00000001000000000000001D.00000020.backup' `/data/pgdata1/../pgdata1.bk20131218/pg_xlog/000000010000000000000021' -> `/data/pgdata1/pg_xlog/000000010000000000000021' -bash-3.2$
リカバリ設定ファイルの作成
最後にリカバリ設定ファイルを作成します。 リカバリ設定ファイルがない状態でPostgreSQLインスタンスを起動すると、 データベースに対するリカバリは実行されません。 PostgreSQLインスタンス起動時に $PGDATA/recovery.conf ファイルが存在する場合のみ リカバリが実行されます。 リカバリ設定ファイル(recovery.conf)はデフォルトでは準備されていませんので、新規に作成します。
PostgreSQLは recovery.conf の「restore_command」にはWALアーカイブファイル名(%f) をWALファイル(%p)にコピーするコマンドを記述します。 ちょうど postgresql.conf の「archive_command」と逆方向のコピーをする形になります。
-bash-3.2$ cd $PGDATA -bash-3.2$ vi recovery.conf
restore_command = 'cp /bkup/pgdata1/pg_arch/%f %p'
PostgreSQLインスタンスの起動
ここまででリカバリの準備が整いましたので、PostgreSQLインスタンスを起動します。 起動時に自動でリカバリが実行され、PostgreSQLインスタンスが起動します。
-bash-3.2$ pg_ctl start -w pg_ctl: 他のサーバが動作中の可能性がありますが、とにかくpostmasterの起動を試みます。 サーバの起動完了を待っています...完了 サーバ起動完了 -bash-3.2$ ps -ef | grep postgres avahi 3201 1 0 Dec17 ? 00:00:00 avahi-daemon: running [postgresql.local] root 7321 6555 0 21:04 pts/1 00:00:00 su - postgres postgres 7322 7321 0 21:04 pts/1 00:00:00 -bash postgres 7368 1 0 21:05 pts/1 00:00:00 /usr/pgsql-9.0/bin/postgres postgres 7369 7368 0 21:05 ? 00:00:00 postgres: logger process postgres 7372 7368 0 21:05 ? 00:00:00 postgres: writer process postgres 7376 7368 0 21:05 ? 00:00:00 postgres: wal writer process postgres 7377 7368 0 21:05 ? 00:00:00 postgres: autovacuum launcher process postgres 7378 7368 0 21:05 ? 00:00:00 postgres: archiver process last was 00000002.history postgres 7380 7368 0 21:05 ? 00:00:00 postgres: stats collector process postgres 7393 7322 0 21:09 pts/1 00:00:00 ps -ef postgres 7394 7322 0 21:09 pts/1 00:00:00 grep postgres -bash-3.2$
ログを確認して「archive recovery complete」と表示されていれば復旧完了です。
※以下の表示例は結果がイマイチかもしれません。すみません。。。
-bash-3.2$ tail -n 30 /data/pgdata1/pg_log/postgresql-20131218.log
(中略)
2013-12-18 21:05:04 JST [7370] LOG: database system was interrupted; last known up at 2013-12-18 20:59:16 JST
2013-12-18 21:05:04 JST [7370] LOG: starting archive recovery
2013-12-18 21:05:05 JST [7370] LOG: restored log file "000000010000000000000020" from archive
2013-12-18 21:05:05 JST [7370] LOG: redo starts at 0/20000020
2013-12-18 21:05:05 JST [7370] LOG: consistent recovery state reached at 0/200000D8
cp: cannot stat `/bkup/pgdata1/pg-arch/000000010000000000000021': No such file or directory
2013-12-18 21:05:05 JST [7370] LOG: record with zero length at 0/2101CE98
2013-12-18 21:05:05 JST [7370] LOG: redo done at 0/2101CBB8
2013-12-18 21:05:05 JST [7370] LOG: last completed transaction was at log time 2013-12-18 21:01:40.291329+09
cp: cannot stat `/bkup/pgdata1/pg-arch/00000002.history': No such file or directory
2013-12-18 21:05:05 JST [7370] LOG: selected new timeline ID: 2
cp: cannot stat `/bkup/pgdata1/pg-arch/00000001.history': No such file or directory
2013-12-18 21:05:05 JST [7370] LOG: archive recovery complete
2013-12-18 21:05:05 JST [7377] LOG: autovacuum launcher started
2013-12-18 21:05:05 JST [7368] LOG: database system is ready to accept connections
-bash-3.2$
リカバリに使われた $PGDATA/recovery.conf ファイルは、 リカバリ終了後に自動で $PGDATA/recovery.done にリネームされます。 そのため、次回PostgreSQLインスタンス起動時に、またリカバリが 実行されてしまうということはありません。
-bash-3.2$ ls -l $PGDATA/recovery* -rw-r--r-- 1 postgres postgres 51 12月 18 20:38 /data/pgdata1/recovery.done -bash-3.2$
以上でリカバリは終了です。