目次
概要
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$
以上でリカバリは終了です。