21.3 备份仓库与保留策略
仓库不是“放备份的目录”,而是一张有依赖、权限、密钥、过期与故障域的 历史图。一个对象存在,不代表它独立可恢复;一个对象过期,也可能让一串 后代失去意义。
21.3.1 全量、差异、增量与过期
三种备份的依赖
以 pgBackRest 术语:
示意:
恢复 I4 需要 F1 + D2 + I4;恢复 I2 需要对应链。工具 catalog 负责
依赖,但 retention policy 必须与这张图一致。
“增量”有多个层面
不要只看备份类型标签:
同一个 incr 单词不保证恢复步骤相同。
full 的价值
full 优点:
- 依赖图短;
- 恢复选择更直接;
- 祖先损坏影响范围小;
- 容易做离线复制或长期固定点。
代价:
- 读取和传输量大;
- checkpoint/I/O 影响;
- repository 增长;
- 大库窗口可能长。
但开启 block incremental、bundle 或 dedup 后,“full backup label”不一定 意味着仓库再次保存一份完整未去重字节。要区分:
本章 formal full:
这反映当前 pgBackRest block/bundle/compression 配置,不代表任何生产数据的 压缩率。
differential 的恢复深度
diff 只依赖 full,所以常用于:
恢复最近日点可能只需 full + diff,而不是一长串 daily incremental。代价是 diff 随 full 之后的累计变化变大。
incremental 的恢复深度
incr 降低单次备份量,但:
- chain 更深;
- 任一依赖损坏影响后代;
- restore 需要更多 metadata/object;
- catalog 与过期规则更关键;
- 小对象延迟可能抵消节省;
- 高频变化数据未必节省很多。
优化 backup window 不能以恢复路径不可测为代价。
backup cadence 与 WAL replay
备份越旧,恢复到“现在”通常需要重放更多 WAL:
因此:
- 更频繁 base/diff 可缩短 replay;
- 更频繁备份增加 source/repository 工作;
- WAL 生成率、CPU、storage latency 影响 replay;
- parallel restore 不等于 parallel WAL replay 无限扩展。
通过生产规模演练测量,而不是从 backup duration 推算 restore duration。
count 与 time retention
pgBackRest repo1-retention-full-type 决定
repo1-retention-full 的解释:
按 count=2 时,新 backup 要先成功,之后才可能 expire 最旧,因此瞬时可见 三份 full。按 time=20 时,需要存在至少一份达到对应年龄的 full 才形成过期 条件。不要把配置数字直接写成没有验证的“覆盖天数”。
differential retention
repo1-retention-diff 按数量控制 diff。依赖被过期时,相应 incremental
也要一起处理。
政策样例:
这只是示例。真正参数要由场景、数据变化、仓库容量和 restore test 得出。
WAL expiration
PITR 需要连续 WAL。pgBackRest 可随 backup expiration 删除不再被保留 backup 所需的 archive。更激进的 archive retention 能省空间,却可能缩短 PITR window。
原则:
一段 WAL 只有相对于某个可用 base 与目标才“有用”。孤立 WAL 不能独立恢复, 但错误删除 bridge segment 会破坏整个窗口。
自动过期的安全条件
在启用 expire 前,至少验证:
- 目标 retention 用例已写成例子;
- catalog 能画出 full/diff/incr dependency;
- newest backup 成功后才触发过期;
- repository 容量允许一次失败重试与过渡峰值;
- legal hold 不会被普通规则删除;
- off-site/immutable copy 的过期独立受控;
- 定期恢复最旧目标;
- dry-run 输出有人审阅;
- 时钟、时区与对象 lifecycle policy 一致;
- 删除权限与写入/恢复权限分离。
对象存储 lifecycle 的隐形删除
即使 pgBackRest retention 正确,bucket lifecycle 也可能:
- 提前删除 object/version;
- 转冷存储导致 RTO 激增;
- 删除 multipart/metadata;
- 与 legal hold 冲突;
- 在 repository catalog 不知情时改变可用性。
基础设施 lifecycle 必须成为同一份恢复设计的受控输入。
最旧目标演练
只恢复 latest backup 不能验证 retention:
生产演练轮换:
21.3.2 校验、加密、不可变与异地副本
四个不同属性
checksum 提供部分 integrity;加密提供 confidentiality;它们都不自动提供 immutability 或 availability。
校验的层次
| 层次 | 例子 | 能发现 | 不能发现 |
|---|---|---|---|
| transport | TLS/object ETag | 传输破坏的一部分 | 业务错误 |
| repository | pgBackRest checksum | object/file mismatch | key 丢失 |
| PostgreSQL page | data checksum | page corruption | 正确写入的错值 |
| backup manifest | pg_verifybackup |
文件/WAL manifest mismatch | target 选择错误 |
| restore start | recovery log | 链条可重放 | 业务不变量 |
| business | token/对账 | 目标事实差异 | 所有未来依赖 |
每层都必要,但结论边界不同。
pgbackrest check
check 用于验证 stanza 配置与 archive path。典型:
注意 pgBackRest 2.59.0 的 check 不接受 --repo=1;本章第一次 formal
尝试正因把 backup/info 的 repo selector 机械复制给 check,以 exit 31
在恢复前安全失败。这个失败保留了两个教学点:
正式成功运行修正命令后继续。
加密在哪里
可能的层次:
每层保护不同攻击面。pgBackRest repository cipher 需要 cipher_pass;如果
配置、备份与密码一起丢失,加密会非常成功地阻止所有人恢复。
密钥生命周期
备份 retention 往往比当前应用 key 生命周期长。密钥设计要回答:
- 谁能加密、谁能解密、谁能删除?
- rotation 后旧备份如何恢复?
- key version 与 backup label 如何关联?
- KMS/secret store 在区域事故中是否独立?
- break-glass 如何审批、审计和定期测试?
- 员工离职、账户冻结和组织恢复如何处理?
- legal deletion 是否通过 key destruction 实现,证据是什么?
不要把 cipher pass 复制到 evidence、工单或书中。本章 evidence 只记录
cipher=aes-256-cbc,不导出密码。
不可变不是只读 ACL
普通权限:
若同一 credential 能写、覆盖、expire 与删除,攻击者拿到它就能破坏历史。
更强设计可能包括:
- object lock / WORM retention;
- versioning;
- 独立账户/项目;
- MFA-delete 或审批;
- writer 无 delete;
- lifecycle role 与 restore role 分离;
- retention policy 受治理;
- audit log 写入另一安全域;
- 定期从不可变副本恢复。
“S3-compatible”不等于实现并启用了这些特性。
不可变也会制造治理问题
设置错误的长期 object lock 会:
- 无法删除敏感数据;
- 产生不可控成本;
- 阻塞环境清理;
- 与法律删除义务冲突。
因此需要:
不可变是政策与控制面组合,不是一个布尔开关。
异地副本的独立性
“异地”至少检查:
两 bucket 位于不同 region,但由同一高权限脚本执行 recursive delete,仍有 共同控制域。
3-2-1 只是启发式
常见经验:
它提醒独立性,但不能替代场景合同。三份都被同一 credential 删除,数量没有 意义;一份真正不可变、离站且可恢复的副本,可能比十份同域复制更有价值。
repository namespace
避免不同 cluster 冲突:
不要把另一个 initdb 出来的 cluster 伪装成旧 cluster 继续向同一 archive
namespace 写入。pgBackRest stanza metadata 与 system ID 检查是保护层;
权限与路径隔离仍要做。
沙箱边界
本章仓库:
所以正式结论带:
能够真实恢复,并不抹掉仓库共同故障。
21.3.3 容量预算、失败告警与责任人
容量不是数据库大小乘份数
粗略预算:
还受:
用历史指标和压力场景建模,不只用当前 pg_database_size。
两个增长率
一个 1 TB 数据库每天只改 1%,与每天 rewrite 500 GB 的数据库,备份策略不同。
原生观测:
配合定时 LSN sample 估算 WAL rate。
带宽预算
需要同时考虑:
backup 能在 4 小时窗口内完成,不代表事故时 restore 也能在 4 小时内完成: 方向、并发、cold retrieval 和 target infrastructure 都不同。
容量水位
至少建立:
阈值应给行动时间:
固定 80%/90% 可能对高速增长系统太晚。
备份失败不是一个布尔告警
分类:
每种 owner 与紧急程度不同。
freshness SLI
示意:
比“backup job success rate 99%”更接近 recoverability。
一次失败后先保护什么
当 backup job 失败:
- 确认 archive 仍连续;
- 确认
pg_wal与 repository 容量; - 保存错误上下文与 catalog;
- 判断现有 restore window 是否仍满足;
- 修复依赖后重试;
- 不要先 expire “腾空间”;
- 若 RPO 已越线,升级 incident。
当 archive 失败:
- 以磁盘耗尽预测为首要风险;
- 保护未归档 WAL;
- 恢复 repository path;
- 确认最大 WAL 前进;
- 安排隔离 restore 验证链条。
RACI
一份实际 owner map:
| 能力 | Accountable | Responsible | Consulted |
|---|---|---|---|
| 业务 RPO/RTO | 业务 owner | SRE/平台 | DBA、安全 |
| PostgreSQL backup config | 平台 owner | DBA/平台 | SRE |
| repository capacity | 存储/平台 owner | 平台 | DBA |
| credential/key | 安全 owner | 安全/平台 | DBA |
| retention/legal hold | 数据治理 | 平台/法务 | 业务 |
| restore runbook | 平台 owner | DBA/SRE | 应用 |
| business validation | 业务 owner | 应用团队 | DBA |
| production cutover | incident/change owner | SRE/平台 | 全方 |
如果 backup 告警只有“DBA 群”负责,区域、密钥、应用验证很可能无人负责。
每日、每周、每季
示意节奏:
频率按 tier 调整,但“从不恢复,只看 job”不属于任何成熟 tier。
可审计政策模板
每个字段都应能找到 evidence,而不只是配置愿望。
小结
仓库的工程对象是:
下一节进入恢复动作本身:怎样从候选 backup 中选择真正能到达 target 的一份, 如何在启动前验证 lineage/WAL,以及为什么 PostgreSQL “一致”仍不足以交付。
上一节:物理备份与 WAL 连续性 · 返回本章目录 · 下一节:恢复流程与验证 · 查看全书目录 · 查看索引中心