仕事でクライアントから不具合報告があったため、修正対応していた。
このサイトはユーザー参加型の小説系コミュニティサイトで、しかも
クライアントはうちの会社の比にならないほどの某大手。
対応終わって、ホッとしてクライアントに連絡したら、その後、
操作ミスでCMS管理画面からデータを削除してしまったようだと
連絡を受けた…。
なんとユーザー画面に表示されるべきものが丸ごと消えている…。
社内のサーバー担当に聞いたら、データベースのバックアップは
運用当初から一切取っていないとのこと…(汗)
前担当からの引継ぎ抜けでやってなかったらしい…。
運用開始から1年たっており、かなりのデータがたまっていたはずだ。
しかもデータはクライアントにとっては資産というべきもの。
バックアップを取っていなかったなんて!
とてもデータを復元出来ないなんて言えない…。
もう笑うしかないと思った(笑)。
損害賠償くらって、うちの会社は倒産するのではないかと
頭をよぎったら、良い方法を見つけた。
PostgreSQLはVaccumをかけていなければ、
トランザクションログをたどって、データを復元できるらしい。
すぐにサーバー担当に実行してもらって何とか復元出来たのだった。
もう生きた心地しなかったよ〜(泣)
胃が痛くなったし、ハラハラしすぎて心臓に違和感感じちゃったし。
疲れました(^^;
参考に決め手の方法となった情報載せときます。
---------------------------------------------
PITR(Point In Time Recovery)
概要
PostgreSQL の PITR 機能を使うと、トランザクションログを使って、データベースへの変更前後の任意の時点に復元することができるため、オペレーションミス等による意図しない変更を復元することができる。
セットアップ
postgresql.conf の編集
archive_commad を有効にし、ログファイルを(安全な)ディレクトリに保存するようにする。
archive_command は WAL を書き込み後、適当なタイミングでよばれるコマンドで、WAL セグメントを別のディレクトリやテープ等に保存するコマンドを記述する。
ここでは単純に cp コマンドを使って /pg_backup にコピーするものとした。実行はデータベースサーバの実行ユーザ権限で行われるので、ディレクトリの所有者を postgres (データベースの実行ユーザ)にした。
# - Archiving -
archive_mode = on # allows archiving to be done
# (change requires restart)
archive_command = 'cp %p /pg_backup/%f' # command to use to archive a logfile segment
archive_timeout = 0 # force a logfile segment switch after this
PostgreSQL サーバを再立ち上げするまで有効にならない。データベースへの変更処理を行うと、トランザクションが /pg_backup にコピーされる。以下のようなファイルができていれば OK
# ls /pg_backup
000000010000000000000038
ベースバックアップを作成する
基準となるデータベースをバックアップする。
バックアップ自体はデータベースディレクトリをコピーするだけだが、いつの時点でのバックアップかをラベリングするため、コピーの開始および終了時にバックアップ中であることを SQL コマンドで宣言する。
バックアップの開始宣言。「BACKUP 2009-03-10」は単なるラベルで
区別のつくものなら何でもよい。
% psql template1
Welcome to psql 8.3.6, the PostgreSQL interactive terminal.
Type: \copyright for distribution terms
\h for help with SQL commands
\? for help with psql commands
\g or terminate with semicolon to execute query
\q to quit
template1=# select pg_start_backup('BACKUP 2009-03-10');
pg_start_backup
-----------------
0/3831D460
(1 row)
データベースディレクトリを適当な場所にコピーする。
# cp -a data /pg_backup/
バックアップの終了宣言
template1=# select pg_stop_backup();
pg_stop_backup
----------------
0/3831D4BC
(1 row)
リカバリー
テストデータの作成
db1=# create table logs (t timestamp);
CREATE TABLE
db1=# insert into logs values ('now'::timestamp);
INSERT 0 1
db1=# insert into logs values ('now'::timestamp);
INSERT 0 1
db1=# insert into logs values ('now'::timestamp);
INSERT 0 1
db1=# insert into logs values ('now'::timestamp);
INSERT 0 1
db1=# select * from logs;
t
----------------------------
2009-03-10 10:19:13.05735
2009-03-10 10:19:22.530281
2009-03-10 10:19:31.248691
2009-03-10 10:19:39.895007
(4 rows)
データの削除
db1=# delete from logs;
DELETE 4
db1=# select * from logs;
t
---
(0 rows)
復元
PostgreSQL を止める
# /etc/rc.d/init.d/postgresql stop
pg_xlog にはアーカイビングされる前のWALが記録されているので、これを安全な場所に退避する。でないと直前の状態に戻せなくなる。
# cp -a pg_xlog /pg_backup
データベースの削除(移動)
# mv data data.orig
ベースバックアップのコピー
cp -a /pg_backup/data .
退避しておいた直前の WAL を戻す。
cp /pg_backup/pg_xlog/* data/pg_xlog/
recovery.conf.sample をコピーし環境に合わせてrecovery.conf を作成する
# cp /usr/share/pgsql/recovery.conf.sample data/recovery.conf
recover.conf の内容 ( /pg_backup に保存したログを書き戻し、2009-03-10 10:19:40 時点の状態にする)
restore_command = 'cp /pg_backup/%f %p'
recovery_target_time = '2009-03-10 10:19:40'
#
PostgreSQL を再立ち上げして中身を確認する。
db1=# select * from logs;
t
----------------------------
2009-03-10 10:19:13.05735
2009-03-10 10:19:22.530281
2009-03-10 10:19:31.248691
2009-03-10 10:19:39.895007
(4 rows)
delete が発行される前の状態(2009-03-10 10:19:40)に戻った。