このエントリーをはてなブックマークに追加

概要

 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

手順

バックアップ

(1) 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$

(2) データの更新

 ベースバックアップ取得後にデータベースに対して追加、更新、削除などが実行されるかと思います。 その後、操作ミスなどによりデータベースファイルを誤って消してしまったことを想定します。

リカバリ

(3) 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$

(4) ベースバックアップの復元

 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$

(5) 最新の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$

(6) リカバリ設定ファイルの作成

 最後にリカバリ設定ファイルを作成します。 リカバリ設定ファイルがない状態で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
ファイル名:$PGDATA/recovery.conf
restore_command = 'cp /bkup/pgdata1/pg_arch/%f %p'

(7) 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$

 以上でリカバリは終了です。