备份、恢复与 PITR
按恢复目标选择逻辑或物理备份,并用演练证明可恢复
选择工具
| 需求 | 工具/方式 | 关键边界 |
|---|---|---|
| 单库、可移植、选择对象 | pg_dump / pg_restore | 不包含集群级角色与 tablespace 定义 |
| 全集群逻辑对象 | pg_dumpall --globals-only 配合各库 dump | 大库恢复慢,需重建索引 |
| 整实例快速恢复 | pg_basebackup 或成熟备份工具 | 版本和平台约束更强 |
| 恢复到某一时间点 | 物理基准备份 + 连续 WAL 归档 | 必须持续验证 WAL 完整性 |
pgBackRest、WAL-G 与 pg_dump 怎么选
| 方案 | 更适合 | 不足以单独证明 |
|---|---|---|
pgBackRest | 自托管实例的 full/differential/incremental、并行备份、多 repository、WAL 与 PITR | 目标 RTO 已达标,密钥和所有 WAL 都可用 |
WAL-G | 对象存储导向的物理备份与 WAL 工作流 | repository 保留、删除保护和恢复正确 |
pg_dump / pg_restore | 逻辑迁移、选择对象、小规模恢复与跨版本导出 | 连续时间点恢复或整实例低 RTO |
| 云平台备份 | 降低基础设施维护量 | 跨账户、跨区域、平台外恢复和全部扩展可恢复 |
不要机械套用固定的每日/每周频率。由 RPO、WAL 生成量、恢复带宽、保留策略和实测 RTO 反推 backup cadence,并保留至少一份独立于主数据库权限边界的副本。
逻辑备份
自定义格式支持并行恢复与选择对象:
pg_dump \
--format=custom \
--file=commerce-20260802.dump \
--dbname='postgresql://backup@db.example/commerce'
pg_restore --list commerce-20260802.dump
createdb commerce_restore_test
pg_restore \
--dbname=commerce_restore_test \
--jobs=4 \
--exit-on-error \
commerce-20260802.dumppg_dump 在导出期间提供一致快照,但只能备份一个 database。角色等全局对象另行备份:
pg_dumpall --globals-only > globals-20260802.sql不要把包含密码哈希的 globals 文件放进普通制品库。
物理备份与 PITR
PITR 需要:可用的基准备份、从基准备份起连续完整的 WAL、正确的恢复配置,以及时间线管理。只保存 WAL 不够;只做 base backup 也无法恢复到任意时间点。
归档命令必须只在安全复制成功后返回 0,并避免覆盖已有文件。对象存储通常需要成熟备份工具管理并发、校验、保留和加密,而不是一条未经监控的 shell 命令。
持续告警 archive failure、缺失 WAL、repository 容量和最近一次可恢复时间。删除旧备份前,让工具按依赖关系计算保留链;不要只按文件日期手工删除。
PITR 分步实操
手工恢复到某个时间点的最小流程:
sudo systemctl stop postgresql
# 把基准备份解压到清空的数据目录
tar -xzf /backup/2026-08-01/base.tar.gz -C "$PGDATA"
touch "$PGDATA"/recovery.signal# postgresql.conf(或 postgresql.auto.conf)
restore_command = 'cp /archive/%f %p'
recovery_target_time = '2026-08-01 14:30:00+08'启动后实例回放 WAL 到目标点并暂停(默认 recovery_target_action = 'pause')。确认数据后执行 SELECT pg_wal_replay_resume(); 完成恢复。时间线处理同样需要演练:每次完成恢复都会产生新的 timeline,归档必须能跟上。
pgBackRest 配置示例
最小 repository 配置:
# /etc/pgbackrest/pgbackrest.conf
[global]
repo1-path=/var/lib/pgbackrest
# 示例值;保留策略应由 RPO 和存储容量推导
repo1-retention-full=4
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=<secret>
[main]
pg1-path=/var/lib/postgresql/18/mainsudo -u postgres pgbackrest --stanza=main stanza-create
sudo -u postgres pgbackrest --stanza=main check
sudo -u postgres pgbackrest --stanza=main --type=full backup
sudo -u postgres pgbackrest --stanza=main --type=incr backup
sudo -u postgres pgbackrest --stanza=main info
# 时间点恢复
sudo systemctl stop postgresql
sudo -u postgres pgbackrest --stanza=main \
--type=time --target='2026-08-01 14:30:00+08' restore
sudo systemctl start postgresqlcheck 会端到端验证 WAL 归档,每次修改配置后都应运行。保留链、加密密钥和 repository 权限在恢复时必须全部可用——丢失 cipher pass 等于丢失整个 repository。
恢复演练
每次演练都在隔离实例上进行——备用主机或测试机的另一个端口,绝不用生产数据目录:
- 把最近一次备份恢复到临时路径,例如
pgbackrest --stanza=main --pg1-path=/tmp/restore-test restore。 - 用独立端口启动一个临时实例:
postgres -D /tmp/restore-test -p 6543。 - 运行下面的校验查询与冒烟测试。
- 确认所需扩展、角色和恢复密钥都可用;单库 dump 不包含集群级角色。
- 停止并删除临时实例。
每次演练记录:备份 ID、起止时间、恢复目标、数据库版本、所需密钥、实际 RTO、可恢复到的最新事务时间、校验查询和异常。
验证至少包括:
SELECT count(*) FROM critical_table;
SELECT min(created_at), max(created_at) FROM critical_table;
SELECT conname, convalidated FROM pg_constraint WHERE NOT convalidated;
SELECT indexrelid::regclass, indisvalid FROM pg_index WHERE NOT indisvalid;再运行应用层只读冒烟测试。行数相同不证明业务关系和权限正确。
副本不是备份
复制会快速复制误删、错误更新和逻辑损坏。备份需要独立保留、删除保护、校验和恢复演练。
Last updated on