PostgreSQL の PITR(ポイントインタイムリカバリ) を試してみる
PostgreSQL の PITR(ポイントインタイムリカバリ) を試してみる。
大まかな流れ
- 事前設定
- WAL archive 設定
- ベースバックアップの作成
- 事件発生!
- リカバリ
WAL archive の設定
通常の WAL は不要になったら(commit/abort 時に)消えてしまうのだが、PITR のために archive directory にためるような設定にする。
通常は耐障害性を考えて、archive ディレクトリは data ディレクトリと別のディスクにすべき。
ディレクトリを作り
% mkdir archive
dbdata/postgresql.conf に archive directory 指定。
ファイルが決して上書きされないように test でチェックしてから archive するように書く。(マニュアル通り)
archive_mode = on
archive_command = 'test ! -f /Users/taro/pgsql/8.3.7.pitr/archive/%f && cp %p /Users/taro/pgsql/8.3.7.pitr/archive/%f'
WAL はトランザクションが完了するなど、安全なタイミングで archive されるのでトラフィックによっては、長い間 archive されない場合もある。
archive_timeout = 60
と設定しておけば、可能ならば60秒おきに強制的に新しい WAL ファイルに切り替わるようになるらしい。
初期バックアップを取る
WAL は以前の状態に対するアクションのログなので、最初の状態をバックアップする必要がある。
まずは pg_start_backup でチェックポイントを作成する。引数は任意の文字列。口授打つのバックアップファイルのパスを指定するのがおすすめと書いてあった。
# SELECT pg_start_backup('dbdata.init.bak'); pg_start_backup ----------------- 0/1000060 (1 row)
この状態で cp コマンドでファイルをバックアップする。
% cp -r dbdata dbdata.init.bak
このとき並行して別の db 操作が動いていても構わない。
cp が終わったら pg_start_backup する。
# SELECT pg_stop_backup(); pg_stop_backup ---------------- 0/2000000 (1 row)
いろいろデータを入れてみよう
ちょっとわざとらしいですが、それぞれの操作をした時刻を合わせて取得しておく。
# CREATE TABLE person (id integer, name text); # select now() ; now ------------------------------- 2009-04-14 16:11:03.546275+09
データ入れる。
=# insert into person values(1, 'higepon'); INSERT 0 1 hige=# insert into person values(2, 'higepon2'); INSERT 0 1 hige=# insert into person values(3, 'higepon3'); INSERT 0 1 hige=# select now() ; now ------------------------------- 2009-04-14 16:12:24.724836+09 (1 row)
さて、そろそろオペレーションミスが発生しそうですね。
# truncate table person;
TRUNCATE TABLE
うわあああ。truncate しちゃった。 rollback も効かないや。
リカバリ
- サーバー止める
- pg_hba.conf をいじってリカバリ中は他のユーザーがアクセスできないようにする
- 念のため data ディレクトリをバックアップする(リカバリに失敗したとき用)
- data ディレクトリとそのサブディレクトリにあるファイルをごっそり消す。(こわいなあ)
- dbdata.init.bak の中身を dbdata に戻す。(ファイルの所有権に注意)
- dbdata/pg_xlog にあるファイルを消す。pg_xlog/archive_status/ は再作成する。
- dbdata/recovery.conf を作成する。中身は戻したい時刻。(指定するのはトランザクション ID でも良い)
- restore_command = 'cp /Users/taro/pgsql/8.3.7.pitr/archive/%f %p'
- recovery_target_time = '2009-04-14 16:13:00 JST'
- サーバースタート
ログファイルを見てみると
LOG: starting archive recovery LOG: restore_command = 'cp /Users/taro/pgsql/8.3.7.pitr/archive/%f %p' LOG: recovery_target_time = '2009-04-14 16:13:00+09' cp: /Users/taro/pgsql/8.3.7.pitr/archive/00000001.history: No such file or directory LOG: restored log file "000000010000000000000000" from archive LOG: automatic recovery in progress LOG: redo starts at 0/441308 LOG: restored log file "000000010000000000000001" from archive LOG: restored log file "000000010000000000000002" from archive LOG: restored log file "000000010000000000000003" from archive LOG: restored log file "000000010000000000000004" from archive LOG: restored log file "000000010000000000000005" from archive LOG: recovery stopping before commit of transaction 392, time 2009-04-14 16:14:25.909294+09 LOG: redo done at 0/5002DC4 LOG: last completed transaction was at log time 2009-04-14 16:12:21.428895+09 cp: /Users/taro/pgsql/8.3.7.pitr/archive/00000002.history: No such file or directory LOG: selected new timeline ID: 2 cp: /Users/taro/pgsql/8.3.7.pitr/archive/00000001.history: No such file or directory LOG: archive recovery complete LOG: database system is ready to accept connections LOG: autovacuum launcher started
recovery が成功したとでた。確認してみよう。
# select * from person; id | name ----+---------- 1 | higepon 2 | higepon2 3 | higepon3
復旧した。