LabHub
学习 学习路径 课程

备份 — 把删掉的数据找回来

回到事故前 30 秒

在 LabHub 中继续学习

目标

真实执行一次误运行 DELETE恢复到事故发生前 30 秒

环境

Pod 中已运行 PostgreSQL 16(5432,数据库 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 를 복사해서 만든다)

步骤

  1. archive_mode = on 并重启
  2. pg_basebackup/root/work/base
  3. 写入两行数据并记录目标时间 → 03-target.txt
  4. 执行 delete from ops_note + pg_switch_wal()
  5. 创建 restore 目录 + recovery.signal
  6. 在 5433 启动并确认(应有两行)
  7. pg_dump 比较 → 07-dump.txt
  8. 总结 → 08-notes.md

必须遵守

启用 WAL 归档

启用 archive_mode,让 WAL 复制到 /root/work/walpg_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() 切换一个 segment 进行确认。

创建基础备份

使用 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 表并插入两行,再把当前时间保存到 /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 推入 archive。

没有 WHERE 的 DELETE 是生产中常见事故。若不调用 pg_switch_wal(),最后一次变更可能尚未归档,恢复无法到达该位置,因为归档只复制已经写满的 segment。

创建恢复副本

把基础备份复制/root/work/restore,设置 restore_commandrecovery_target_timeport = 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 의 값>'recovery_target_action = 'promote'archive_mode = offport = 5433不要忘记关闭 archive_mode,否则恢复副本会覆盖原始 archive。

确认被删除的数据恢复

在 5433 启动恢复副本并检查 ops_note 行数,必须为两行。原始实例(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。确认该 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。dump 是创建瞬间的快照,因此包含删除后的状态。如果只有昨晚的 dump,RPO 就是 24 小时。

总结缺少什么就无法恢复

/root/work/08-notes.md 中至少写三行:PITR 所需的三个组成部分、archive_command 把失败报告为成功时会发生什么,以及从 RPO 角度看只保留 dump 意味着什么。

正文必须包含 WALRPO타임라인。最后一句概括了整门课程:从未恢复验证过的备份,不是备份。