TT Lab
はじめる
学ぶ 学習パス コース

バックアップ — 消したデータを戻す

事故の30秒前へ

TT Labで続きを見る

目標

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をコピーして作る)という意味です。

ステップ

  1. archive_mode = on + 再起動
  2. pg_basebackup → /root/work/base
  3. データ2行 + 目標時刻 → 03-target.txt
  4. delete from ops_note + pg_switch_wal()
  5. restoreディレクトリ + recovery.signal
  6. 5433で起動して確認(2行であること)
  7. pg_dumpと比較 → 07-dump.txt
  8. まとめ → 08-notes.md

必ず守ること

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行が、このコースのすべてです。復旧してみたことのないバックアップは、バックアップではありません。