21.3 备份仓库与保留策略
仓库不是“放备份的目录”,而是一张有依赖、权限、密钥、过期与故障域的 历史图。一个对象存在,不代表它独立可恢复;一个对象过期,也可能让一串 后代失去意义。
21.3.1 全量、差异、增量与过期
三种备份的依赖
以 pgBackRest 术语:
full
不依赖同仓库的更早 backup set
diff
依赖最近 full,保存相对 full 的变化
incr
依赖最近一次可作为父级的 backup,保存相对父级的变化示意:
F1
├── D1
│ ├── I1
│ └── I2
├── I3
└── D2
└── I4
F2
└── I5恢复 I4 需要 F1 + D2 + I4;恢复 I2 需要对应链。工具 catalog 负责
依赖,但 retention policy 必须与这张图一致。
“增量”有多个层面
不要只看备份类型标签:
logical incremental
应用/CDC 按变化导出
file-level incremental
只复制 mtime/size/checksum 判定变化的文件
block incremental
只保存改变的数据块
PostgreSQL 18 native incremental
WAL summaries + manifests + pg_combinebackup
pgBackRest incr
pgBackRest repository dependency and restore semantics同一个 incr 单词不保证恢复步骤相同。
full 的价值
full 优点:
- 依赖图短;
- 恢复选择更直接;
- 祖先损坏影响范围小;
- 容易做离线复制或长期固定点。
代价:
- 读取和传输量大;
- checkpoint/I/O 影响;
- repository 增长;
- 大库窗口可能长。
但开启 block incremental、bundle 或 dedup 后,“full backup label”不一定 意味着仓库再次保存一份完整未去重字节。要区分:
logical database size
backup delta read
repository delta written
repository total referenced size本章 formal full:
logical size 36,121,841 bytes
repository delta 4,539,288 bytes这反映当前 pgBackRest block/bundle/compression 配置,不代表任何生产数据的 压缩率。
differential 的恢复深度
diff 只依赖 full,所以常用于:
weekly full
daily diff
intra-day incr恢复最近日点可能只需 full + diff,而不是一长串 daily incremental。代价是 diff 随 full 之后的累计变化变大。
incremental 的恢复深度
incr 降低单次备份量,但:
- chain 更深;
- 任一依赖损坏影响后代;
- restore 需要更多 metadata/object;
- catalog 与过期规则更关键;
- 小对象延迟可能抵消节省;
- 高频变化数据未必节省很多。
优化 backup window 不能以恢复路径不可测为代价。
backup cadence 与 WAL replay
备份越旧,恢复到“现在”通常需要重放更多 WAL:
[ T_{recovery} \approx T_{retrieve\ backup} +T_{assemble} +T_{replay\ WAL} +T_{checkpoint} ]
因此:
- 更频繁 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
保留多少 full backup set
time
以天为阈值保留 full按 count=2 时,新 backup 要先成功,之后才可能 expire 最旧,因此瞬时可见 三份 full。按 time=20 时,需要存在至少一份达到对应年龄的 full 才形成过期 条件。不要把配置数字直接写成没有验证的“覆盖天数”。
differential retention
repo1-retention-diff 按数量控制 diff。依赖被过期时,相应 incremental
也要一起处理。
政策样例:
full: weekly, retain by time 35 days
diff: daily, retain 7
incr: every 6 hours
WAL: follow oldest retained recovery anchor
month-end logical archive: separate 13 months这只是示例。真正参数要由场景、数据变化、仓库容量和 restore test 得出。
WAL expiration
PITR 需要连续 WAL。pgBackRest 可随 backup expiration 删除不再被保留 backup 所需的 archive。更激进的 archive retention 能省空间,却可能缩短 PITR window。
原则:
expire backup dependency graph first
derive which WAL is no longer useful
dry-run aggressive archive expiration
never delete WAL merely because it is "old"一段 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:
choose oldest required target
-> identify required backup chain
-> retrieve cold/off-site objects
-> obtain historical key
-> replay full WAL span
-> validate business marker生产演练轮换:
latest target
oldest target
random time target
target across timeline switch
target just before destructive transaction
target whose objects are in cold tier21.3.2 校验、加密、不可变与异地副本
四个不同属性
integrity
bytes 未损坏/未被替换
confidentiality
未授权者不能读取
immutability
在保留窗口内,包括高权限主体也不能轻易删除/改写
availability
事故时对象、密钥、网络和权限仍可用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。典型:
sudo -iu postgres \
pgbackrest --stanza=pg-test --log-level-console=info check注意 pgBackRest 2.59.0 的 check 不接受 --repo=1;本章第一次 formal
尝试正因把 backup/info 的 repo selector 机械复制给 check,以 exit 31
在恢复前安全失败。这个失败保留了两个教学点:
same tool != every command accepts same option
successful check != successful restore正式成功运行修正命令后继续。
加密在哪里
可能的层次:
client-side/repository encryption by backup tool
object storage server-side encryption
disk/volume encryption
transport TLS
application/column encryption每层保护不同攻击面。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
普通权限:
backup writer can put
restore reader can get
operator can delete若同一 credential 能写、覆盖、expire 与删除,攻击者拿到它就能破坏历史。
更强设计可能包括:
- object lock / WORM retention;
- versioning;
- 独立账户/项目;
- MFA-delete 或审批;
- writer 无 delete;
- lifecycle role 与 restore role 分离;
- retention policy 受治理;
- audit log 写入另一安全域;
- 定期从不可变副本恢复。
“S3-compatible”不等于实现并启用了这些特性。
不可变也会制造治理问题
设置错误的长期 object lock 会:
- 无法删除敏感数据;
- 产生不可控成本;
- 阻塞环境清理;
- 与法律删除义务冲突。
因此需要:
retention class
legal hold process
minimum/maximum lock
authorized bypass
evidence and audit
test bucket before production不可变是政策与控制面组合,不是一个布尔开关。
异地副本的独立性
“异地”至少检查:
physical region
cloud/account/project
identity provider
KMS/key
network/control plane
operator role
automation blast radius
object lifecycle
billing/organization dependency两 bucket 位于不同 region,但由同一高权限脚本执行 recursive delete,仍有 共同控制域。
3-2-1 只是启发式
常见经验:
3 copies
2 media/system types
1 off-site它提醒独立性,但不能替代场景合同。三份都被同一 credential 删除,数量没有 意义;一份真正不可变、离站且可恢复的副本,可能比十份同域复制更有价值。
repository namespace
避免不同 cluster 冲突:
repository
-> stanza
-> database/system-id lineage
-> archive id
-> timeline/WAL不要把另一个 initdb 出来的 cluster 伪装成旧 cluster 继续向同一 archive
namespace 写入。pgBackRest stanza metadata 与 system ID 检查是保护层;
权限与路径隔离仍要做。
沙箱边界
本章仓库:
one local MinIO
S3-compatible
AES-256-CBC repository cipher
shared laptop/hypervisor context
object lock not validated
cross-region copy not validated
independent credential domain not validated所以正式结论带:
EX21-REPOSITORY-NOT-IMMUTABLE能够真实恢复,并不抹掉仓库共同故障。
21.3.3 容量预算、失败告警与责任人
容量不是数据库大小乘份数
粗略预算:
[ Capacity = B_{full} +\sum B_{diff} +\sum B_{incr} +WAL_{window} +Metadata +Versions +SafetyMargin ]
还受:
database growth
change rate and full-page images
compression/dedup
block incremental
bundle
index churn
vacuum/rewrite
WAL generated by bulk load/DDL
object versioning
failed/in-progress backup
multipart residue
cold tier overhead用历史指标和压力场景建模,不只用当前 pg_database_size。
两个增长率
data growth rate
determines future full/restore size
WAL generation rate
determines archive bandwidth, RPO exposure and replay work一个 1 TB 数据库每天只改 1%,与每天 rewrite 500 GB 的数据库,备份策略不同。
原生观测:
SELECT now(),
pg_current_wal_lsn(),
pg_walfile_name(pg_current_wal_lsn());
SELECT archived_count, failed_count,
last_archived_wal, last_archived_time,
last_failed_wal, last_failed_time
FROM pg_stat_archiver;配合定时 LSN sample 估算 WAL rate。
带宽预算
需要同时考虑:
source read throughput
source network egress
repository write/read throughput
archive sustained throughput
restore download throughput
WAL replay CPU/storage
shared production contentionbackup 能在 4 小时窗口内完成,不代表事故时 restore 也能在 4 小时内完成: 方向、并发、cold retrieval 和 target infrastructure 都不同。
容量水位
至少建立:
repository used / total
growth per day/week
forecast days to full
oldest/newest backup
oldest/newest recoverable target
WAL archive backlog
pg_wal filesystem free
backup duration and bytes
restore duration by representative size
object lifecycle transitions阈值应给行动时间:
warning when forecast leaves enough time to provision
critical before next backup/archive can exhaust capacity固定 80%/90% 可能对高速增长系统太晚。
备份失败不是一个布尔告警
分类:
scheduler did not start
backup started but failed
backup completed but required WAL missing
repository inaccessible
archive delayed
checksum/integrity failure
retention did not expire
retention expired too much
credential/key near expiry
restore drill failed
business validation failed每种 owner 与紧急程度不同。
freshness SLI
示意:
age_of_latest_successful_base
age_of_last_independently_archived_wal
duration_of_archive_backlog
days_since_last_successful_restore
age_of_oldest_proven_restore_target比“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 群”负责,区域、密钥、应用验证很可能无人负责。
每日、每周、每季
示意节奏:
continuous
WAL/archive/capacity alert
daily
latest backup, duration, bytes, catalog status
weekly
dependency/retention review, sampled checksum
monthly
automated isolated latest/selected restore
quarterly
representative business validation and oldest target
annually or major change
regional/break-glass/cutover exercise频率按 tier 调整,但“从不恢复,只看 job”不属于任何成熟 tier。
可审计政策模板
service: orders
tier: critical
scenarios:
logical_error:
rpo: named/audited transaction boundary
rto_historical_query: 60m
region_loss:
rpo: 5m
rto_read_write: 4h
backup:
implementation: pgBackRest
full: weekly
diff: daily
incr: 6h
wal_archive: continuous
repository:
primary: object-store-a
immutable_copy: object-store-b
failure_domain: separate account and region
encryption_key: independent-dr-key
retention:
operational_pitr: 35d
monthly_logical: 13m
validation:
latest_restore: monthly
oldest_target: quarterly
regional_cutover: annual
owners:
platform: team-db
business_validation: team-orders
key: team-security每个字段都应能找到 evidence,而不只是配置愿望。
小结
仓库的工程对象是:
backup dependency graph
+ continuous WAL window
+ integrity
+ confidentiality
+ immutability
+ independent availability
+ capacity
+ ownership下一节进入恢复动作本身:怎样从候选 backup 中选择真正能到达 target 的一份, 如何在启动前验证 lineage/WAL,以及为什么 PostgreSQL “一致”仍不足以交付。
上一节:物理备份与 WAL 连续性 · 返回本章目录 · 下一节:恢复流程与验证 · 查看全书目录 · 查看索引中心