跳到正文

备份恢复与运维:备份的价值只在恢复那一刻 ​

一句话:备份的目标不是「有一份文件」,而是在约定的 RPO/RTO 内把库恢复到某个一致点;逻辑备份管对象,物理备份 + WAL 归档管时间点。

适用 PostgreSQL 16/17。命令中的主机、路径、库名按环境替换。

为什么需要 ​

误删表、误更新、磁盘损坏、机房故障,对应的恢复手段不同:

  • 误删一张表:逻辑备份或 PITR 到误删前。
  • 整个实例损坏:基础备份 + WAL 归档。
  • 主库宕机:流复制切换(见 03 篇),不是备份。

没有恢复演练的备份不可信。备份文件存在、命令返回 0,都不等于能在目标 RTO 内恢复。

核心机制 ​

逻辑备份与物理备份 ​

维度逻辑备份(pg_dump)物理备份(pg_basebackup)
内容SQL/自定义格式的对象和数据整个数据目录的文件块
粒度库、schema、表整个实例
跨版本通常可以(大版本差异需验证)必须同大版本
恢复速度慢,要重新执行 SQL/建索引快,文件级恢复
PITR不支持支持(配合 WAL 归档)
典型用途单表恢复、迁移、小库大库全量恢复、搭备库

pg_dump 在导出时使用一致性快照,并持有 ACCESS SHARE 锁;它不阻塞 DML,但长备份会阻塞 DDL。--no-sync 只是不等待输出文件刷盘,不是「不保证一致性」,不要混淆。

pg_basebackup 会触发检查点,然后流式复制数据文件;-X stream 同时收集备份期间产生的 WAL。备份期间数据库可读写,但检查点可能带来 IO 尖刺,--checkpoint=fast 可以缩短备份时间、加大尖刺。

WAL 归档与 PITR ​

PITR(Point-In-Time Recovery)需要三个要素:

  1. 一个基础备份(pg_basebackup 或 pgBackRest 的全量备份)。
  2. 从备份开始到目标时间点的连续 WAL 归档。
  3. 恢复目标:时间、LSN、XID 或命名还原点。

恢复时,PostgreSQL 从基础备份的 backup_label 确定起点,用 restore_command 不断取 WAL 重放,直到 recovery_target_*。每次恢复/提升会生成新的时间线(timeline),防止新 WAL 和旧历史混淆。

PostgreSQL 12+ 不再使用 recovery.conf:把恢复参数写进 postgresql.conf(或 postgresql.auto.conf),用 recovery.signal 触发恢复。standby.signal 则表示进入持续 standby 模式。

RPO 与 RTO ​

  • RPO(Recovery Point Objective):能容忍丢失多长时间的数据。异步复制下,未传到备库的 WAL 就是 RPO;每日逻辑备份的 RPO 约 24 小时。
  • RTO(Recovery Time Objective):从故障到恢复服务的时间。取决于检测、切换、恢复数据量、重放 WAL、应用重连。
方案RPORTO(经验值)
每日逻辑备份约 24 小时小时级,取决于库大小和索引重建
基础备份 + WAL 归档约一个 WAL 切换周期分钟到小时
异步流复制 + 自动切换秒级到分钟级数十秒
同步流复制 + 自动切换0(同步备库确认后)数十秒,依赖 quorum

RTO 数字必须用真实库演练,不能照搬。

最小上手 ​

逻辑备份与恢复 ​

bash
# 自定义格式:压缩、支持并行恢复、可选择性恢复
pg_dump -h 127.0.0.1 -p 5432 -U postgres -Fc -f /backup/app.dump appdb

# 并行恢复(自定义/目录格式)
pg_restore -h 127.0.0.1 -U postgres -d appdb_restore -j 4 /backup/app.dump

pg_dump -Fd -j 是并行导出;pg_restore -j 是并行恢复。纯 SQL 格式(-Fp)只能 psql -f 顺序执行,不支持 pg_restore -j。

物理备份 ​

bash
# 基础备份到空目录,同时流式收集 WAL
pg_basebackup -h 10.0.0.11 -U replicator \
  -D /backup/base/20261024 -Fp -Xs -P

# 校验基础备份(PostgreSQL 13+,需要 backup_manifest)
pg_verifybackup /backup/base/20261024

pg_basebackup 的目标目录必须为空。-Ft 生成 tar 包,-Fp 生成普通目录;-R 会顺便写好 standby.signal 和 primary_conninfo,适合直接搭备库。PostgreSQL 17 起支持增量基础备份(pg_basebackup --incremental),更早版本需要 pgBackRest/Barman 做增量。

归档与 PITR ​

ini
# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /wal_archive/%f && cp %p /wal_archive/%f'
archive_timeout = 60

archive_mode 需要重启;archive_command 可以重载。test ! -f 防止覆盖已归档的 WAL。

恢复步骤(PostgreSQL 12+):

bash
# 1. 停库,保护现场,清空/移走原数据目录
pg_ctl -D /var/lib/pgsql/16/data stop

# 2. 还原基础备份到数据目录(-Fp 直接复制目录内容)
cp -a /backup/base/20261024/. /var/lib/pgsql/16/data/

# 3. 创建恢复信号
touch /var/lib/pgsql/16/data/recovery.signal

# 4. 在 postgresql.conf 配置 restore_command 和 recovery_target_time
#    (可选 recovery_target_action = 'promote')

# 5. 启动并观察日志
pg_ctl -D /var/lib/pgsql/16/data start

验证:SELECT pg_is_in_recovery(); 提升后应为 f;SELECT timeline_id FROM pg_control_checkpoint(); 恢复后时间线会递增。

生产动作 ​

  • 备份策略:每周全量 + 每日增量/差异 + 连续 WAL 归档;WAL 保留时间必须覆盖最老的基础备份。pgBackRest 用 --type=full/incr/diff、--repo1-retention-full;Barman 用 barman backup / barman check。
  • 恢复演练:至少每季度在独立实例做一次 PITR,记录实际 RTO;只跑 pg_verifybackup 不够,它验证文件完整性,不验证业务可用性。
  • 归档监控:pg_stat_archiver 看 failed_count、last_archived_time、last_failed_time;归档失败会导致 PITR 在缺口处停下。
  • 逻辑备份的一致性:pg_dump 默认使用一致性快照;需要更严格的串行化语义时用 --serializable-deferrable,但它可能等待。
  • 大库恢复:先恢复基础备份,再重放 WAL;恢复期间不要对外开放连接。恢复后 ANALYZE,并检查序列值、扩展、权限。
  • 不要用备库代替备份:误删会同步到备库;备库只解决机器/磁盘故障,不解决逻辑错误。

四类高频运维故障 ​

  • 磁盘只涨不降、DELETE 后不回收 → pg_stat_user_tables 的 n_dead_tup/n_live_tup 和 last_autovacuum → Vacuum 追不上 → 按表调小 autovacuum_vacuum_scale_factor(默认 0.2),必要时 pg_repack,不要高峰做 VACUUM FULL。详见 11 篇。
  • 数据库突然只读、报事务 ID 相关错误 → SELECT age(datfrozenxid) FROM pg_database; → 接近 2 亿(autovacuum_freeze_max_age)→ 立即安排 VACUUM FREEZE,不要靠重启硬扛。
  • 报 too many clients → pg_stat_activity 按 state 计数对比 max_connections(默认 100)→ 连接泄漏或池配置错误 → 修连接池,不要只调大上限。详见 08 篇。
  • 迁移后某些查询反而更慢 → EXPLAIN (ANALYZE, BUFFERS) 对比 rows 预估与实际 → 统计信息过期或索引不匹配 → ANALYZE、建扩展统计/复合索引。JSONB 查询慢则确认是否用了 @> 而不是 ->>。详见 05、08 篇。

边界 ​

  • 逻辑备份不能做 PITR:它只有导出时刻的快照,没有连续 WAL。
  • 物理备份不能跨大版本:数据文件不兼容;跨版本用逻辑备份/逻辑复制/pg_upgrade。
  • pg_basebackup 不是增量(17 之前):大库每天全量成本高,用 pgBackRest/Barman;17+ 的增量也要配合 pg_combinebackup 使用。
  • WAL 归档断了,PITR 就断了:缺一个 WAL 段,恢复会在那里停下;归档失败必须告警。
  • 没有演练的备份不算备份:文件存在、校验通过,都不等于能在 RTO 内恢复业务。
  • 不要删除比最老基础备份更早的 WAL:否则那份备份无法恢复到一致点。

讲清楚 ​

备份分两条线:逻辑备份用 pg_dump 导出对象和数据,适合单表恢复、迁移、小库;物理备份用 pg_basebackup 复制整个数据目录,配合 WAL 归档才能做 PITR。PITR 的三要素是基础备份、连续 WAL、恢复目标;PostgreSQL 12+ 用 recovery.signal 触发恢复,不再有 recovery.conf。RPO 决定最多丢多少数据:每日逻辑备份约 24 小时,异步复制是未传 WAL,同步复制可以做到 0;RTO 决定多久恢复,必须用真实库演练。运维上最该盯的是 WAL 归档失败、死元组比例、事务 ID 回卷余量和连接数。最后记住:备库不是备份,误删会同步;没有恢复演练的备份,只是磁盘上的一份文件。

把一门技术讲透到既懂也会用