事故の30秒前へ
目標
DELETEを誤って実行したあと、事故の30秒前に巻き戻す作業を、実際に行います。
環境
このPodには、PostgreSQL 16がすでに起動しています(5432、DB labdb、ユーザーlab。スーパーユーザーです)。リストア先は、同じPodの中に、5433で別に起動します。
export PATH=/usr/lib/postgresql/16/bin:$PATH
export PGDATA=/var/lib/postgresql/data
psql -h 127.0.0.1 -U lab -d labdb
作業ディレクトリ
/root/work/wal 아카이브된 WAL
/root/work/base 베이스 백업 (원본 — 건드리지 않는다)
/root/work/restore 복구본 (base 를 복사해서 만든다)
このコードブロックの韓国語の説明は、順に、アーカイブされたWAL、ベースバックアップ(原本であり、触らない)、リストア先(baseをコピーして作る)という意味です。
ステップ
archive_mode = on+ 再起動pg_basebackup→/root/work/base- データ2行 + 目標時刻 →
03-target.txt delete from ops_note+pg_switch_wal()restoreディレクトリ +recovery.signal- 5433で起動して確認(2行であること)
pg_dumpと比較 →07-dump.txt- まとめ →
08-notes.md
必ず守ること
- 元の上にリストアしません。別のディレクトリ、別のポート。
- リストア先の設定には、
archive_mode = offを必ず入れてください。入れないと、リストア先が元のアーカイブを上書きします。 - ステップ4で
pg_switch_wal()を忘れないでください。アーカイブは、書き終わったセグメントだけをコピーするので、最後の変更がまだ渡っていません。
WALアーカイブを有効にする
archive_modeを有効にして、WALが/root/work/walにコピーされるようにしてください。pg_stat_archiver.archived_countが0より大きい必要があります。
labアカウントはスーパーユーザーです。psql -h 127.0.0.1 -U lab -d postgres -c "alter system set archive_mode = on"のようにして、archive_commandはtest ! -f /root/work/wal/%f && cp %p /root/work/wal/%fにしてください。test ! -fが上書きを防ぎます。archive_modeは再起動が必要です: pg_ctl -D /var/lib/postgresql/data restart -m fast -w。そのあと、select pg_switch_wal()で1つ押し出して確認してください。
ベースバックアップを取る
pg_basebackupで/root/work/baseに、データディレクトリ全体を取得してください。
pg_basebackup -h 127.0.0.1 -U lab -D /root/work/base -Fp -Xs -P。-Fpは展開した形式(plain)、-Xsはバックアップ中に生じたWALも一緒にストリーミングして、それだけでも起動できるようにします。あとのリストアで、このディレクトリをコピーして使います。元は触りません。
戻る時刻を残す
ops_noteテーブルを作って、行を2つ入れてください。そのあと、現在の時刻を/root/work/03-target.txtに残します。この時刻が、復旧の目標になります。
create table ops_note(id serial primary key, note text, at timestamptz default now())。時刻は、psql -tAc "select now()" > /root/work/03-target.txtで残してください。入れてから1秒以上経ったあとで時刻を記録して初めて、その挿入が目標時点の中に入ります。
事故を起こす
ops_noteの行をすべて削除してください(delete from ops_note)。テーブルは残します。そして、pg_switch_wal()で、その変更を含むWALをアーカイブに押し出してください。
WHEREのないDELETEは、実務で実際によく起きる事故です。pg_switch_wal()を呼ばないと、最後の変更がまだアーカイブされておらず、復旧がその地点まで進めません。アーカイブは書き終わったセグメントだけをコピーするからです。
リストア先を作る
ベースバックアップを/root/work/restoreにコピーし、restore_command・recovery_target_time・port = 5433を設定したあと、recovery.signalを作ってください。
cp -r /root/work/base /root/work/restore && chmod 700 /root/work/restore。設定はrestore/postgresql.auto.confに書きます: restore_command = 'cp /root/work/wal/%f %p'、recovery_target_time = '<03-target.txt 의 값>'(プレースホルダーは03-target.txtの値です)、recovery_target_action = 'promote'、archive_mode = off、port = 5433。archive_modeをオフにするのを忘れないでください。そうしないと、リストア先が元のアーカイブを上書きします。
消したデータが生きているかを見る
リストア先を5433ポートで起動して、ops_noteの行数を確認してください。2つである必要があります。元(5432)は、相変わらず0個です。
pg_ctl -D /root/work/restore -l /tmp/restore.log start -w -t 60。起動しなければ、/tmp/restore.logを見てください。たいてい、restore_commandのパスか、目標時刻の形式の問題です。確認: psql -h 127.0.0.1 -p 5433 -U lab -d labdb -c 'select * from ops_note'。
論理バックアップではなぜダメかを見る
今(事故のあと)の元を、pg_dump -Fcで/root/work/labdb.dumpに取ってください。このダンプの中のops_noteが何行かを確認して、07-dump.txtに書いてください。
pg_dump -h 127.0.0.1 -U lab -Fc -d labdb -f /root/work/labdb.dump。一覧はpg_restore -l /root/work/labdb.dump。ダンプは取った瞬間の写真なので、すでに削除されたあとの状態が入ります。昨夜のダンプしかなかったなら、RPOは24時間という意味です。
何がなければ戻ってこられなかったか
/root/work/08-notes.mdに3行以上。PITRに必要な3つの部品、archive_commandが失敗を成功と報告すると何が起きるか、そしてRPOの観点で、ダンプだけを置くことが何を意味するか。
本文にWAL、RPO、타임라인(3つ目は韓国語で「タイムライン」という意味です)が入っている必要があります。最後の1行が、このコースのすべてです。復旧してみたことのないバックアップは、バックアップではありません。