跳至内容
21.1 从恢复场景设计备份

21.1 从恢复场景设计备份

备份设计最容易犯的错误,是从一个漂亮的日历开始:

周日全备
周一到周六增量
保留 14 天

它回答了“工具何时运行”,却没有回答:

什么会丢?
丢了什么算业务损失?
要回到哪个边界?
由谁判断边界正确?
依赖也丢失时怎么办?
多快恢复到什么能力?

正确顺序是从场景与真相出发,再选择恢复机制、保留和调度。

21.1.1 误删、介质故障、区域故障与合规留存

先定义“损失”

数据库恢复不是把字节放回磁盘,而是重新建立被业务接受的事实。至少区分:

logical loss
  数据库仍运行,但某些正确事实被删除、覆盖或错误变更

physical loss
  数据文件、WAL、设备或整个集群不可用/不可信

site loss
  数据库、控制面、接入层和本地备份一起不可用

historical obligation
  必须证明某个历史版本可恢复、可查询或已按政策删除

不同损失的 truth source 不同。误删一行时,最可信的边界可能来自审计事件; 存储毁坏时,最可信的边界是仓库中最后完整基础备份与连续 WAL;区域故障时, 本地仓库本身不再是可用前提。

场景一:误删与逻辑破坏

典型事件:

DELETE FROM orders;
UPDATE account SET balance = 0;
DROP TABLE customer;
deploy buggy migration;
application writes wrong currency or tenant id;

主库、流复制副本和同步副本都会忠实重放这些操作。HA 可能保持服务在线, 却更快地把错误复制到每份在线副本。

误删恢复要先问:

  1. 错误事务的开始、提交和影响范围是什么?
  2. 目标是整个集群回退,还是只取回一张表/一批行?
  3. 目标时刻之后有哪些正确交易不能丢?
  4. 如何把旧事实与当前事实合并?
  5. 序列、外键、触发器、审计与外部系统如何一致?

常见安全路径不是“原地 PITR 回退生产”,而是:

restore historical cluster in isolation
  -> validate target boundary
      -> export affected logical set
          -> compare with current production
              -> reviewed merge or repair

原地回退会同时删除误操作之后的所有正确提交,通常扩大损失。

场景二:介质、文件系统或集群丢失

典型事件:

data volume lost
filesystem corruption
all HA members share failed storage
operator removes whole cluster
encryption layer/key unavailable
malware changes data and online copies

这时要恢复的是整个物理集群。所需链条通常为:

compatible PostgreSQL runtime
+ one usable base backup
+ every required WAL segment
+ timeline history
+ tablespace/path mapping
+ repository credential and encryption key
+ configuration and identity material

注意最后两项不一定在 PostgreSQL 物理备份内。官方连续归档文档明确提醒, postgresql.confpg_hba.confpg_ident.conf 的手工修改不由 WAL 恢复。平台声明、证书、服务发现、KMS/IAM 与 DNS 也需要独立保存。

场景三:区域或控制域故障

区域故障不是“把同一恢复命令放到另一台机器”:

source region unavailable
local object store unavailable
local DNS/control plane unavailable
operator identity federation degraded
secrets/KMS endpoint unavailable
network dependency changed
capacity not pre-provisioned

如果数据库与备份仓库在同一机房、云账户、管理员凭据或密钥域,所谓 “远程对象存储”仍可能是共同故障。

区域场景的前提矩阵至少包括:

依赖源域丢失时是否仍可用证据
基础备份是/否异地对象清单、定期读取
WAL是/否最大已复制 WAL、延迟
解密密钥是/否独立保管与 break-glass 测试
PostgreSQL 包/镜像是/否固定版本仓库
Pigsty 声明是/否版本化、离站
DNS/证书是/否独立控制面
应用依赖是/否DR dependency map
人员权限是/否异地登录演练

只有“对象在另一个 bucket”远远不够。

场景四:合规留存与法律冻结

合规问题不等于“把备份留久一点”。需要先区分:

operational recovery retention
  为误删、故障与日常恢复保留

historical record retention
  为审计、诉讼、监管或业务档案保留

legal hold
  正常过期规则暂时不能删除特定材料

right-to-delete / minimization
  到期后必须删除或不可再识别

物理备份以整个 cluster 为粒度,单个数据主体的删除很难立刻传播到所有历史 备份。合规方案可能需要:

  • 受控的短期物理恢复窗口;
  • 更长期、字段经过选择与脱敏的逻辑档案;
  • 按租户/数据域分离;
  • 密钥销毁策略;
  • legal hold 与正常过期的冲突处理;
  • 恢复访问的审批、审计和二次删除。

不要让 DBA 独自解释法律语义。数据 owner、安全、法务与平台团队要共同签署 retention class。

场景卡,而不是一句“灾备”

为每个场景写同一张卡:

id: accidental-delete-orders
trigger: confirmed destructive transaction against orders
authoritative_boundary:
  source: audit event + restore point
  timezone: UTC
scope: selected tenant and time range
maximum_tolerated_loss:
  committed_correct_orders: zero
service_target:
  historical cluster queryable: 60 minutes
  repaired rows in production: 4 hours
dependencies:
  - base backup and continuous WAL
  - audit event identity
  - isolated restore capacity
  - reviewed logical merge procedure
stop_conditions:
  - target transaction ambiguous
  - WAL gap
  - post-target correct orders cannot be reconstructed
proof:
  - restored marker boundary
  - row and amount reconciliation
  - approved repair change
owner: data-platform + orders-domain

recovery-scenarios.json 提供本章四类机器可读样例。没有 stop_conditions 的 runbook 很容易在压力下把“不知道”伪装成“应该没问题”。

同一个事故可能需要两条恢复路径

例如误删订单:

path A: service continuity
  current production remains online

path B: historical reconstruction
  isolated PITR -> export -> compare -> repair

例如区域故障:

path A: promote designed DR replica
  lower RTO, possibly different RPO/consistency contract

path B: restore off-site backup
  slower, but independent historical recovery

HA、DR 与 backup 可以组合,但不能互相替名。

21.1.2 RPO、RTO、恢复粒度与保留周期

RPO:允许回退多远

令:

t_loss     事故发生或最后可信事实时间
t_recover  实际可恢复边界

时间口径可写为:

[ RPO_{actual}=t_{loss}-t_{recover} ]

但它不是简单的 backup interval:

daily base backup + continuous WAL
  RPO 主要由 WAL 最后耐久位置决定,不是 24 小时

daily logical dump only
  RPO 可能接近 24 小时

streaming replica
  对主机故障可能接近复制延迟
  对误删可能是 0 秒地复制了错误,无法提供历史点

生产 RPO 必须带场景:

primary process loss RPO
single-AZ loss RPO
repository outage RPO
operator logical error RPO
region loss RPO

“RPO = 5 分钟”却不说明事故类型,是不完整的合同。

WAL archive 的 RPO

连续归档场景中,粗略地:

[ RPO_{archive} \approx t_{failure}-t_{last\ durable\ independent\ WAL} ]

需要强调 durableindependent

  • WAL 在主库 pg_wal 中,不代表主机丢失后仍可取;
  • archive command 返回成功,不代表对象存储副本已跨域;
  • 对象写入完成,不代表 KMS/credential 在事故中可用;
  • pg_stat_archiver 的累计失败数不等于“当前失败”,要看最近成功/失败时序 和 backlog。

低流量系统还会遇到 segment 未填满。archive_timeout 或显式 pg_switch_wal() 可以缩短时间窗口,但过短会制造大量完整长度的归档对象。

RTO:恢复到哪种能力

完整恢复时间不是 restore 命令运行时间:

[ RTO_{\text{business}} \ge T_{\text{detect}} +T_{\text{decide}} +T_{\text{provision}} +T_{\text{retrieve}} +T_{\text{replay}} +T_{\text{validate}} +T_{\text{cutover}} +T_{\text{dependency}} ]

可以同时定义多个里程碑:

里程碑完成条件
repository selected备份、WAL、key 和 target 已审核
bytes restoredpgBackRest 文件阶段完成
consistentPostgreSQL 到达一致恢复点
read-only可以接受只读查询
promotedpg_is_in_recovery() = false
data validated引擎与业务不变量通过
service cut over受控端点连接到正确角色
backlog cleared积压与补偿完成

本章正式实验测到:

restore copy                  2.758 s
start -> first read-only      0.963 s
start -> promoted             1.319 s

若只记录前两个数字,会漏掉验证、路由、应用依赖和积压,也会把只读窗口误报为 “恢复完成”。

恢复粒度

至少有四种粒度:

cluster
  物理备份/PITR 常见粒度;包含 cluster 内所有数据库

database/schema/table
  逻辑导出或从隔离物理恢复中再导出

row/business object
  比较、审计、补偿与应用语义

service capability
  read-only、read-write、reporting、limited tenant 等

PostgreSQL 物理 WAL 是 cluster 级历史。不能告诉恢复引擎“只重放某张表的 正确事务”。pgBackRest 的 database include/排除能力也不是任意表级 PITR; 选择性恢复的语义必须认真核对限制。

target 精度不等于 truth 精度

PostgreSQL 可按:

time
transaction ID
LSN
named restore point
immediate consistency
end of available WAL

停止恢复。但技术 target 再精确,如果业务事件不明确,也不能证明正确。

例如:

10:00:00 application request sent
10:00:01 database transaction committed
10:00:02 external payment confirmed
10:00:03 audit pipeline wrote event

“恢复到 10:00:02”到底包含什么,取决于时区、提交时间、inclusive 语义与 外部系统。命名点可以降低实验歧义,但生产误删通常只能事后从日志、XID、 LSN 或审计重建边界。

保留周期不是 PITR 窗口的同义词

假设“保留 14 天全备”,仍不能自动推出:

过去 14 天每一秒都可恢复

还需要:

  • 至少一份在目标之前结束的可用基础备份;
  • 从该备份起到目标的连续 WAL;
  • timeline history;
  • 未丢失的依赖备份;
  • 可用的解密密钥和仓库权限;
  • 与目标 PostgreSQL 版本兼容的恢复环境。

真实 PITR window 是这些集合的交集。

恢复点频度、版本数与日历跨度

三个常被混淆的量:

capture cadence
  多久产生一个新逻辑/物理基线

version count
  保留多少组 backup

calendar coverage
  最旧可恢复事实距现在多远

retention_full=2 按 count 解释,与按 time 解释完全不同;差异/增量依赖还会 影响一组备份何时能安全过期。应把政策写成可测试的例子:

at 2026-08-01 12:00 UTC
  must restore any named daily checkpoint since 2026-07-18
  must restore any WAL time since 2026-07-25
  must retain month-end logical archive for 7 years

然后定期真的选最旧目标恢复。

分级服务目标

不是所有数据库都应买同一种恢复成本:

tier场景示例RPORTO机制
critical支付主账秒/分钟级分钟级HA + 连续 WAL + 异地仓库 + 高频演练
important订单业务分钟级小时级连续 WAL + 物理备份 + 选择性恢复
standard内部应用小时级当日日备 + 合理 WAL/逻辑导出
reconstructable派生分析可重算天级上游真相 + schema/code + optional backup

分级的结果不是降低严谨性,而是让成本与真实损失匹配。

目标反推设计

对每个 tier 反推:

RPO
  -> WAL archive latency / dump cadence / replication mode

RTO
  -> restore bandwidth / provisioned capacity / runbook automation

granularity
  -> physical, logical, audit or application repair path

retention
  -> backup dependency graph + WAL policy + legal hold

failure domain
  -> repository placement + credential + key independence

proof
  -> drill frequency + oldest target + business invariant

这比先决定“全备还是增量”更接近工程问题。

21.1.3 逻辑、物理、快照和副本的职责边界

没有一种副本解决全部恢复问题

机制主要内容典型粒度优势主要盲区
pg_dumpSQL/归档格式逻辑对象database/object可选择、可迁移、可检查慢;非 cluster 物理 PITR
pg_dumpall全局对象与多个库的 SQLcluster logicalroles/tablespaces 辅助大规模恢复慢;无 WAL
physical base backup数据文件物理状态cluster快、完整、可配 WAL版本/平台耦合;粗粒度
WAL archive变更历史clusterPITR、连续恢复必须连续;依赖 base
storage snapshotblock/volumevolume快速 capture/clone一致性、跨卷、WAL 与快照语义
streaming replica在线物理历史尾部cluster低 RTO、读扩展复制误删;非独立历史
logical replication/CDC选择性变更流table/event异构、下游重建DDL/序列/删除/slot 等边界

设计的关键是组合,而不是选一个“最好”的工具。

逻辑备份适合什么

pg_dump 在一个一致性快照中读取数据库,可以:

  • 选择 schema/table;
  • 以 custom/directory 格式并行恢复;
  • 跨部分 PostgreSQL 版本迁移;
  • 检视 DDL 与数据;
  • 从隔离 PITR 中导出被误删的对象。

但逻辑备份:

  • 不是数据目录文件副本;
  • 不含用于物理重放的控制信息;
  • 不能接到 WAL archive 上继续重放;
  • 通常不覆盖所有 cluster-wide 配置与运行状态;
  • 大库导出/导入和索引重建可能远慢于物理恢复;
  • 恢复顺序、owner、extension、privilege 与 external dependency 仍要处理。

PostgreSQL 官方文档明确说明 pg_dump/pg_dumpall 不能作为连续归档物理 恢复链的一部分。

物理备份适合什么

物理备份复制 cluster 数据文件,并依靠 WAL 把不一致的文件时间切片恢复到 一致点。它保留:

all databases in cluster
catalogs and physical relation state
transaction status
extension physical objects inside cluster
system identifier lineage

它适合:

  • 大型数据库快速整库恢复;
  • PITR;
  • 创建 standby/clone;
  • 保留完整引擎语义。

但通常要求同一大版本与兼容架构/页格式,并以 cluster 为恢复单位。物理 恢复后再做逻辑选择,是误删恢复常见组合。

PostgreSQL 18 原生增量不要和工具增量混为一谈

PostgreSQL 18 的 pg_basebackup --incremental 依赖:

earlier backup manifest
WAL summaries covering the required LSN interval
pg_combinebackup at restore preparation
all earlier dependent backups
normal WAL recovery requirements

这是一套 PostgreSQL 原生机制。pgBackRest 的 full/diff/incr、block incremental、bundle 与 repository metadata 是另一套实现和依赖图。

讨论“我们做增量备份”时,必须说清:

which tool
which version
dependency chain
restore assembly step
expiration owner

不能因为术语相同就互换 runbook。

快照要回答一致性

单卷快照可能在 block 层原子,但数据库语义还要问:

  • PostgreSQL 是否运行中?
  • 数据、WAL、tablespace 是否跨多个卷?
  • 各卷快照是否同一 consistency group?
  • 是否调用 pg_backup_start/stop 或工具协议?
  • 快照克隆后如何恢复与识别 timeline?
  • 快照控制面与主存储是否共同故障?
  • 是否定期挂载并启动验证?

“云盘快照成功”不是数据库一致性的证据。一个 crash-consistent snapshot 也许能通过 crash recovery,但不能自动提供任意 PITR 或跨卷一致性。

Replica 为什么不是 backup

流复制的目标是把当前历史低延迟复制到其他实例:

primary DELETE wrong rows
  -> WAL
      -> replica replays same DELETE

它可以:

  • 降低实例/主机故障的 RTO;
  • 在同步策略下改善某些故障的 RPO;
  • 分担读;
  • 作为备份来源,降低主库读取压力。

它不能单独:

  • 保留误操作之前的历史点;
  • 对抗影响全部成员的错误配置;
  • 对抗同一账户/区域/恶意管理员;
  • 证明长期 retention;
  • 替代隔离恢复。

延迟副本可增加逻辑错误反应窗口,但依然需要:

delay guarantee
pause/stop authority
monitoring that does not auto-heal away the delay
protection from direct reads/writes
independent backup for other failures

CDC 不是免费备份

事件流或 logical replication 能帮助重建某些数据,但要验证:

  • 初始快照从哪里来;
  • DDL 是否同步;
  • TRUNCATE/DELETE 是否保留足够语义;
  • sequence、large object 与 extension state;
  • slot 丢失或 lag;
  • exactly-once 是否只是消费端幂等;
  • 下游是否共享同一个逻辑错误。

它更适合作为另一条可重建历史,而不是未经证明的整库恢复替代品。

一份常见的组合

HA replicas
  handle selected availability failures

physical full/diff/incr + WAL
  handle cluster restore and PITR

logical export
  handle object-level portability and long-term selected records

audit/event history
  identify business boundary and support repair

off-site immutable copy
  handle control-domain and destructive repository loss

restore drills
  prove that all of the above compose

“多种机制”不等于重复浪费;前提是每种都有明确场景和 owner。

选择问题

面对一个需求,按顺序问:

1. loss is logical, physical, site-wide, or compliance?
2. recover whole cluster or selected facts?
3. need historical point or latest state?
4. how independent must the copy be?
5. what PostgreSQL/version compatibility exists?
6. what target precision can be observed?
7. how will business correctness be proven?
8. what is the controlled return-to-service path?

可能的答案:

selected rows from yesterday
  isolated physical PITR -> logical export -> reviewed merge

whole cluster after storage loss
  physical backup + WAL -> replacement infrastructure

cross-major migration
  logical dump/restore or logical replication, not physical replay

low-RTO host failure
  HA promotion, while independent backup remains separate

seven-year selected archive
  policy-specific logical record, not indefinite operational WAL by default

本节验收问题

在进入物理原理前,应能回答:

  1. 你的前三个恢复场景是什么?
  2. 每个场景的 authoritative boundary 来自哪里?
  3. RPO/RTO 的起止点和完成能力是什么?
  4. 哪些损失会被 replica 同步复制?
  5. 当前 retention 是否真的形成连续 PITR window?
  6. 配置、密钥、声明和应用依赖存放在哪里?
  7. 哪些结论只有实际 restore 才能证明?

如果答案仍是“每天有备份”,还没有完成设计。

小结

恢复体系从业务损失开始:

scenario defines truth
truth defines target
target defines mechanism
mechanism defines dependencies
dependencies define retention and placement
proof defines the drill

下一节进入物理链条:一份在线基础备份为什么能够是不一致的文件切片, WAL 又如何把它变成一个可选择时间点的 PostgreSQL 历史。


返回本章目录 · 下一节:物理备份与 WAL 连续性 · 查看全书目录 · 查看索引中心

最后更新于