跳至内容
21.3 备份仓库与保留策略

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 前,至少验证:

  1. 目标 retention 用例已写成例子;
  2. catalog 能画出 full/diff/incr dependency;
  3. newest backup 成功后才触发过期;
  4. repository 容量允许一次失败重试与过渡峰值;
  5. legal hold 不会被普通规则删除;
  6. off-site/immutable copy 的过期独立受控;
  7. 定期恢复最旧目标;
  8. dry-run 输出有人审阅;
  9. 时钟、时区与对象 lifecycle policy 一致;
  10. 删除权限与写入/恢复权限分离。

对象存储 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 tier

21.3.2 校验、加密、不可变与异地副本

四个不同属性

integrity
  bytes 未损坏/未被替换

confidentiality
  未授权者不能读取

immutability
  在保留窗口内,包括高权限主体也不能轻易删除/改写

availability
  事故时对象、密钥、网络和权限仍可用

checksum 提供部分 integrity;加密提供 confidentiality;它们都不自动提供 immutability 或 availability。

校验的层次

层次例子能发现不能发现
transportTLS/object ETag传输破坏的一部分业务错误
repositorypgBackRest checksumobject/file mismatchkey 丢失
PostgreSQL pagedata checksumpage corruption正确写入的错值
backup manifestpg_verifybackup文件/WAL manifest mismatchtarget 选择错误
restore startrecovery log链条可重放业务不变量
businesstoken/对账目标事实差异所有未来依赖

每层都必要,但结论边界不同。

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 contention

backup 能在 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 失败:

  1. 确认 archive 仍连续;
  2. 确认 pg_wal 与 repository 容量;
  3. 保存错误上下文与 catalog;
  4. 判断现有 restore window 是否仍满足;
  5. 修复依赖后重试;
  6. 不要先 expire “腾空间”;
  7. 若 RPO 已越线,升级 incident。

当 archive 失败:

  1. 以磁盘耗尽预测为首要风险;
  2. 保护未归档 WAL;
  3. 恢复 repository path;
  4. 确认最大 WAL 前进;
  5. 安排隔离 restore 验证链条。

RACI

一份实际 owner map:

能力AccountableResponsibleConsulted
业务 RPO/RTO业务 ownerSRE/平台DBA、安全
PostgreSQL backup config平台 ownerDBA/平台SRE
repository capacity存储/平台 owner平台DBA
credential/key安全 owner安全/平台DBA
retention/legal hold数据治理平台/法务业务
restore runbook平台 ownerDBA/SRE应用
business validation业务 owner应用团队DBA
production cutoverincident/change ownerSRE/平台全方

如果 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 连续性 · 返回本章目录 · 下一节:恢复流程与验证 · 查看全书目录 · 查看索引中心

最后更新于