实战场景与恢复路径总览
| 场景 |
关键前提 |
首选方法 |
关键命令或要点 |
| 事务未提交 |
仍在同一个会话/事务中 |
直接回滚 |
在 psql 中执行 ROLLBACK; |
| 已提交但未被 VACUUM 清理 |
表尚未发生自动清理 |
读取“已删除但未清理”的元组 |
安装并使用 pg_dirtyread 扩展导出到新表 |
| 已 VACUUM 但 WAL 含整页镜像 FPW |
参数 full_page_writes=on 且 WAL 归档/保留完整 |
从 WAL 提取 FPW 并重建表页 |
pg_waldump --save-fullpage 提取,覆盖到表文件后用 pg_dirtyread 导出 |
| 有基础备份 + WAL 归档 |
已配置 WAL 归档 |
时间点恢复 PITR |
配置 restore_command 与 recovery_target_time 启动恢复 |
| 只有逻辑备份 |
有 pg_dump 导出 |
逻辑恢复 |
psql -f backup.sql 或 pg_restore |
| WAL 损坏/无归档且无法回滚 |
无备份、WAL 不可用 |
最后手段:pg_resetwal |
仅作兜底,可能丢数据,务必先全量备份当前目录 |
以上路径按可行性排序,优先尝试事务回滚与 pg_dirtyread,其次利用 WAL/FPW,再到备份恢复,最后才是 pg_resetwal。
场景一 事务未提交
- 现象:误删后未执行 COMMIT;,或仍在同一会话。
- 处理:在 psql 中直接回滚。
- 示例:
- BEGIN;
- DELETE FROM orders WHERE id = 100;
- ROLLBACK; – 数据立即恢复
- 要点:一旦提交,DELETE 仅将元组标记为“已删除”(设置 xmax),进入可被清理阶段,无法用 ROLLBACK 恢复。
场景二 已提交但未被 VACUUM 清理
- 原理:DELETE 后数据仍在数据页中,直到 VACUUM/autovacuum 回收。关键时间窗取决于表大小和参数 autovacuum_vacuum_scale_factor(默认 20%)与 autovacuum 周期(常见约 1 分钟量级)。
- 步骤(Debian 12,示例库名 sales,表名 customers):
- 安装扩展(以 PostgreSQL 16 为例,其他版本替换为对应版本号)
- sudo apt install postgresql-16-dirtyread
- 在目标库创建扩展
- CREATE EXTENSION pg_dirtyread;
- 将“已删除但未清理”的数据导出到新表
- CREATE TABLE recovered_customers AS
SELECT * FROM pg_dirtyread(‘customers’)
AS t(id integer, name text, email text, …); – 列定义需与原表一致
- 校验后回灌
- – 校验
SELECT COUNT(*) FROM recovered_customers WHERE email LIKE ‘%@example.com’;
- – 回灌到原表(建议先备份原表或在一个事务中校验)
INSERT INTO customers SELECT * FROM recovered_customers
WHERE id NOT IN (SELECT id FROM customers);
- 限制:一旦 autovacuum 运行并回收了该页,pg_dirtyread 将无法读取被清理的元组。
场景三 已 VACUUM 但 WAL 含整页镜像 FPW
- 前提:参数 full_page_writes=on(默认开启),且 WAL 文件(含 FPW)仍保留或可获取。
- 步骤:
- 定位对象标识
- 数据库 OID:SELECT oid FROM pg_database WHERE datname = current_database();
- 表 relfilenode:SELECT relfilenode FROM pg_class WHERE relname = ‘customers’;
- 当前 WAL LSN:SELECT pg_current_wal_lsn();
- 从 WAL 提取整页
- pg_waldump --save-fullpage=fpw
–relation=<db_oid>/
/var/lib/postgresql/16/main/pg_wal/00000001000000000000000A
- 重建表文件并注入 FPW
- 在临时实例或离线环境创建同结构空表(不导入数据),获取其 relfilenode;
- 停止数据库,将提取的 FPW 覆盖到对应表文件(路径通常为 base/<db_oid>/),修正属主属组为 postgres:postgres;
- 启动数据库,使用 pg_dirtyread 从新表导出被删数据,再回灌到生产表。
- 说明:FPW 中仍带有删除标记(xmax),因此仍需借助 pg_dirtyread 读取并筛选。若 WAL 轮转导致所需段缺失,则无法继续。
场景四 有基础备份 + WAL 归档的时间点恢复 PITR
- 前提:已配置 WAL 归档(archive_mode=on,archive_command 正确),并保有基础备份(如 pg_basebackup 或文件系统拷贝)。
- 步骤(Debian 常见数据目录 /var/lib/postgresql/16/main):
- 准备恢复目录并恢复基础备份
- sudo systemctl stop postgresql
- sudo -u postgres rsync -a /backup/base_2025-12-24/ /var/lib/postgresql/16/main/
- 配置恢复参数(postgresql.auto.conf 或 recovery.conf)
- restore_command = ‘cp /archive/%f %p’
- recovery_target_time = ‘2025-12-25 10:20:00+08’ – 误删前的时间点
- recovery_target_timeline = ‘latest’
- 启动到恢复模式并自动回放
- sudo systemctl start postgresql
- 观察日志,确认已达目标时间点并自动进入只读恢复完成状态
- 如为备用库演练,可在达到目标后执行 SELECT pg_wal_replay_resume(); 继续回放
- 校验后提升为主库(如需要)
- 在备库上执行:SELECT pg_promote();
- 要点:PITR 是最稳妥、可验证、可回滚的恢复方式;务必确保归档连续性与基础备份一致性。
场景五 只有逻辑备份的恢复
- 全库逻辑备份恢复
- pg_dumpall -U postgres -f /backup/full_$(date +%F).sql
- 恢复:psql -U postgres -f /backup/full_2025-12-25.sql
- 单库/自定义格式备份恢复
- 备份:pg_dump -Fc -f db.pgdump dbname
- 恢复:pg_restore -d dbname db.pgdump
- 适用:无物理备份、仅需部分库/表、或跨大版本迁移。
场景六 WAL 损坏或无归档的最后手段 pg_resetwal
- 警告:可能导致数据丢失或WAL 不一致,仅在确认无其他恢复路径时作为兜底。
- 步骤:
- 全量备份当前数据目录
- sudo cp -a /var/lib/postgresql/16/main /var/lib/postgresql/16/main_bak_$(date +%F)
- 停止数据库
- sudo systemctl stop postgresql
- 执行重置(请先确认 PGDATA 路径)
- sudo -u postgres pg_resetwal -D /var/lib/postgresql/16/main -f
- 启动并尽快做一致性校验与全量备份
- sudo systemctl start postgresql
- 建议:重置后立刻做一次 pg_dump 全量备份,防止再次崩溃导致不可恢复。
关键检查与常用命令清单
- 检查是否开启整页写入:SHOW full_page_writes;
- 查看当前 WAL LSN:SELECT pg_current_wal_lsn();
- 查看归档命令与会话参数:SHOW archive_command; ! env | grep PG
- 查看表与数据库标识:
- SELECT oid, datname FROM pg_database;
- SELECT relname, relfilenode FROM pg_class WHERE relname = ‘your_table’;
- 观察恢复进度与状态:
- 查看日志:journalctl -u postgresql -f
- 在恢复中:SELECT pg_is_in_recovery();
- 达到目标后提升:SELECT pg_promote();
预防与运维建议
- 备份策略:每日 pg_dump 逻辑备份 + 每周 pg_basebackup 物理备份,异地/离线保存。
- 启用 WAL 归档:archive_mode=on,archive_command 可靠(如 cp/scp 到归档目录),定期校验归档可用性。
- 控制 autovacuum:对关键表可临时调高阈值或禁用(谨慎),为误删争取时间窗。
- 权限与流程:最小权限、变更走工单与复核、生产操作前先在测试环境演练。
- 监控告警:对 WAL 积压、备份失败、磁盘空间、autovacuum 异常设置告警。