21.5 用 pgBackRest 交付备份策略
Pigsty 负责把 PostgreSQL、pgBackRest、仓库、归档、调度、日志和监控组合成 可交付基线;pgBackRest 负责 backup/archive/restore 机制;PostgreSQL 仍然 定义 WAL、recovery、timeline 与业务数据语义。
三层不要混淆:
PostgreSQL
physical history and recovery semantics
pgBackRest
repository, backup sets, archive transport, restore orchestration
Pigsty
declarative delivery, scheduling, service integration and observability21.5.1 仓库、策略、调度与凭据
从 Pigsty 声明开始
当前 Pigsty 的核心入口包括:
pgbackrest_enabled: true
pgbackrest_method: minio # or local/custom
pgbackrest_repo:
minio:
type: s3
s3_endpoint: sss.pigsty
s3_region: us-east-1
s3_bucket: pgsql
path: /pgbackrest
storage_port: 9000
block: y
bundle: y
bundle_limit: 20MiB
bundle_size: 128MiB
cipher_type: aes-256-cbc
retention_full_type: time
retention_full: 14这里只展示非 secret 结构。s3_key_secret 与 cipher_pass 必须来自受控
secret source,不能提交到公开仓库、截图或 evidence。
参数随 Pigsty 版本演进。使用时以目标 tag 的参数参考为准,不能拿当前网页 替历史安装保证。
local 与 MinIO
Pigsty 文档给出的常见方式:
local
local POSIX repository, default path /pg/backup
minio
S3-compatible repository, optional MinIO service
custom
pgBackRest supports other repository backends/config职责差异:
| 方式 | 优势 | 必须显式接受的风险 |
|---|---|---|
| local same host/storage | 简单、低延迟 | 主机/磁盘共同故障 |
| shared local/NFS | 集中 | mount/锁/网络/同域 |
| MinIO/S3-compatible | object API、独立部署可能性 | endpoint、credential、object semantics |
| cloud object store | 跨域与 durability 选择 | 账户/KMS/费用/egress/lifecycle |
pgbackrest_method=minio 不自动证明 MinIO 位于独立故障域。
stanza
pgBackRest stanza 把一个 PostgreSQL cluster 与 repository metadata 关联:
pgbackrest --stanza=pg-test stanza-create
pgbackrest --stanza=pg-test check
pgbackrest --stanza=pg-test infoPigsty 在启用备份组件时交付配置/stanza。current 文档给出:
./pgsql.yml -t pg_backup用于对已存在 cluster 启用相关 subtask;真正执行前:
- 固定 Pigsty repo/tag;
- 使用正确 inventory 与 limit;
- 先 diff/plan 变更;
- 确认不会删除/重建现有 stanza;
- 保护 secret output。
删除 cluster 与 stanza
Pigsty 文档提示,移除 primary 时可能删除 pgBackRest stanza,可用相应参数保留 backup。删除 cluster 的动作与删除 backup 历史是两个授权:
remove database service
!= authorize deleting recovery history所有 pgsql-rm.yml / pg_rm_backup 动作都应进入 destructive review。本章
不执行。
backup 命令
Pigsty 提供 /pg/bin/pg-backup:
pg-backup # documented default/incremental behavior
pg-backup full
pg-backup diff
pg-backup incr原生 pgBackRest:
sudo -iu postgres \
pgbackrest --stanza=pg-test --repo=1 \
--type=full --log-level-console=info backup使用 wrapper 的好处是平台约定一致;使用原生命令的好处是 exact option 清晰。本章 formal 固定原生命令并把版本、label、duration 与 source hash 写入 evidence。
调度
Pigsty 用 pg_crontab 声明:
pg_crontab:
- '00 01 * * 1 /pg/bin/pg-backup full'
- '00 01 * * 2-7 /pg/bin/pg-backup'本章沙箱实际观察:
Monday 01:00 full
other days 01:00 default backup调度要回答:
- 时区;
- primary role 切换后谁执行;
- concurrent/overlap lock;
- missed schedule;
- retry/backoff;
- load window;
- full/diff/incr policy;
- output/log rotation;
- alert source。
cron entry 存在不是 job 成功证据。
primary 与 role change
HA cluster 中 backup job 不应因为原 primary 降为 replica 就盲目继续。平台 wrapper/配置应识别角色与 pgBackRest topology。演练切换后检查:
which node owns cron
which node is repository stanza's database endpoint
archive push source
backup-from-standby policy第 20 章切回原基线后,本章在 pg-test-1 执行 formal full。
async archive 与 spool
pgBackRest 可用 async archive push/get:
PostgreSQL archive command
-> pgBackRest spool queue
-> repository worker好处是降低 postmaster archive command 的同步等待;代价是多一层队列状态。
观察:
spool path
archive-push async log
queue size/age
repository max WAL
pg_stat_archiver
pg_wal free验证 restore 时应使用独立 spool path,避免测试实例与 live archive worker 共享状态。本章:
/data/pg36-ch21-restore/<run>/spool凭据
典型 secret:
S3 access key/secret
repository cipher pass
repository TLS client material
remote host key
database backup/replication credential
KMS token配置文件最低要求:
- owner/group 与 mode;
- 不被普通 exporter/log collector 读取;
- command line/log 自动 redaction 验证;
- rotation;
- break-glass restore;
- 不与 source destruction role 共用;
- 不进入
pgbackrest info的公开 projection。
本章 remote pgBackRest console 会把 secret 显示为 <redacted>,但 formal
evidence 根本不保存原始 console,只保存结构化无 secret 结果。
仓库 TLS 与 CA
S3-compatible endpoint 应验证:
TLS enabled
expected CA
hostname/SAN
certificate rotation
clock
no silent downgrade本章沙箱配置有 repository CA path,但未把完整 transport security 作为 生产验收;第 23 章继续。
声明与有效状态
三份证据:
inventory declaration
generated /etc/pgbackrest config
effective command/catalog behavior不能只看其中一个。生成配置可能漂移,声明可能未应用,运行命令也可能被环境 变量或额外 conf.d 覆盖。
安全投影应保留:
stanza
repo type/path class
endpoint class
cipher type
retention type/value
block/bundle
archive async
spool path去掉所有 secret value。
21.5.2 备份状态、归档状态与容量观察
pgbackrest info
人读:
sudo -iu postgres \
pgbackrest --stanza=pg-test --repo=1 info机器读:
sudo -iu postgres \
pgbackrest --stanza=pg-test --repo=1 --output=json info关注:
stanza status code/message
backup/restore locks
repository id/cipher
database version and repository key
archive id/min/max
backup label/type/error
timestamp start/stop
archive start/stop
logical and repository bytes
prior/reference dependencyJSON 仍可能含 raw system ID;公开 evidence 应转成 equality relation。
label 解读
示例:
20260729-201041F常见 suffix:
F full
D differential
I incremental不要只解析名字推断成功;同时看 catalog error=false、status、archive 和
实际恢复。
check
sudo -iu postgres \
pgbackrest --stanza=pg-test --log-level-console=info check它能触发/检查 archive path 与配置。不同 command 的 options 不完全相同:
info/backup/restore accept --repo=1
check in pgBackRest 2.59.0 rejects --repo=1把一串“通用参数”复制给所有命令是危险习惯。
PostgreSQL 原生交叉验证
SELECT archived_count,
last_archived_wal,
last_archived_time,
failed_count,
last_failed_wal,
last_failed_time
FROM pg_stat_archiver;
SELECT pg_current_wal_lsn(),
pg_walfile_name(pg_current_wal_lsn());对照:
PostgreSQL last archived
pgBackRest archive max
current WAL
spool queue不同 observation 可能短暂错开,要用时间戳和 queue 解释。
累计失败数
本章沙箱:
archived_count > 0
failed_count = 21
last successful time > last failed time这说明过去有失败,当前最近归档成功。正确告警不是:
failed_count > 0 forever critical而是:
failure counter increased recently
and/or last failure later than last success
and/or archive maximum stops advancing while WAL advances
and/or spool/backlog/free-space breachesbackup freshness
计算:
now - latest successful backup stop还要按类型:
latest full age
latest diff age
latest any backup age
oldest retained full一份最新 incremental 可能依赖过旧 full;只看 latest label 隐藏 chain 风险。
archive freshness
低流量时:
last archive time old
current WAL same segment不一定 backlog。高流量时:
last archive time recent
but repository is many segments behind仍可能越过 RPO。结合 rate 和 segment distance。
容量
源端:
df -h /pg/data /pg
du -sh /pg/data/pg_walrepository:
used bytes
object count
growth forecast
version/lock overhead
cold tier
retention expiryrestore target:
df -h /data
df -i /data本章 .13 的 /data 有充足空间,正式 restore 只有约 36 MB;这不能证明
生产大库空间规划。
日志
Pigsty 常见 pgBackRest log path:
/pg/log/pgbackrest/分类:
backup
expire
archive-push-async
archive-get-async
restore日志要集中,但 redaction 后再进入平台。错误排查保留 exec-id、command
version、stanza 与 phase。
dashboard 与 alert
Pigsty 提供 PGSQL PITR 等 dashboard/monitoring 入口。图表用于趋势与定位, 机器验收仍回到:
- PostgreSQL catalog;
- pgBackRest JSON;
- repository/storage fact;
- real restore evidence。
看板绿不等于 restore proof。
观察矩阵
| 信号 | warning | critical/action |
|---|---|---|
| latest full age | 接近 policy | 越过恢复合同 |
| archive max lag | 上升 | RPO 越线/磁盘风险 |
pg_wal free | forecast shrink | 可能 PANIC |
| repository free | forecast shrink | 下一备份不可完成 |
| backup duration | trend regression | window/RTO risk |
| failed count delta | new failure | inspect/retry |
| restore drill age | 接近周期 | recoverability unproven |
| key expiry | rotation window | future restore blocked |
本章 evidence capture
capture.py 默认只读:
PG36_EVIDENCE_DIR=/new/path \
static/labs/ch21/task.sh capture它采集:
Patroni topology
PostgreSQL archive/current WAL/settings
sanitized pgBackRest catalog
no raw system ID
no credential它明确输出:
recoverability = not-proven-by-capture因为 capture 没有执行 restore。
21.5.3 在隔离目标而不是原集群上恢复
Pigsty 的恢复入口
当前 Pigsty 文档提供:
manual pg-pitr prompt/script path
pgsql-pitr.yml playbook path文档说明,熟悉配置时可使用自动 playbook,否则建议逐步手工方式。其本质 原因是恢复 target、source 与 destructive action 需要人理解,不应让 automation 隐藏。
示意:
./pgsql-pitr.yml \
-e '{"pg_pitr": {"time": "2026-07-29 20:10:44+00"}}'这类 playbook 可能停止、清空、重建目标 instance。不要在 live cluster 上 为了练习运行。
当前文档 target forms
Pigsty pg_pitr 映射:
pg_pitr: {}
pg_pitr: { time: "2026-07-29 20:10:44+00" }
pg_pitr: { lsn: "0/200002D0" }
pg_pitr: { xid: "250000", exclusive: true }
pg_pitr: { name: "before_release" }
pg_pitr: { type: "immediate" }使用前核对目标 Pigsty tag 的 exact behavior,以及 exclusive 到
recovery_target_inclusive 的映射。
为什么本章不直接调用 destructive playbook
本章目标是验证备份,而不是替换服务。正式设计:
source cluster remains running
restore under a brand-new path
no Patroni
no DCS
no TCP
no service endpoint
archive_mode=off
stop after proof
retain directoryPigsty 提供配置、pgBackRest 与 repository;本章用底层 pgBackRest 对 fresh path 恢复,以精确控制隔离边界。
formal restore command
结构化示意:
sudo -iu postgres pgbackrest \
--stanza=pg-test \
--repo=1 \
--set=20260729-201041F \
--type=name \
--target=pg36_ch21_<run>_keep \
--target-action=promote \
--target-timeline=latest \
--archive-mode=off \
--pg1-path=/data/pg36-ch21-restore/<run>/data \
--spool-path=/data/pg36-ch21-restore/<run>/spool \
--log-path=/data/pg36-ch21-restore/<run>/log \
restore不要直接复制 placeholder。正式 runner 生成并验证 exact run ID/path,拒绝 已存在目录。
启动覆盖
live Pigsty PostgreSQL config 含:
hba_file=/pg/data/pg_hba.conf
ident_file=/pg/data/pg_ident.conf
log path under /pg/log/postgres
TLS path under /pg/cert
listen_addresses=0.0.0.0
port=5432
standby primary_conninfo/slot若直接启动 restored config,会碰 live path、网络与复制配置。正式 runner 显式覆盖:
listen_addresses = ''
port = 55432
unix_socket_directories = '<private>/socket'
unix_socket_permissions = 0700
hba_file = '<private>/pg_hba.restore.conf'
ident_file = '<restored>/pg_ident.conf'
ssl = off
archive_mode = off
primary_conninfo = ''
primary_slot_name = ''
shared_preload_libraries = ''
logging_collector = off
cluster_name = 'pg36-ch21-restore'同时携带 source recovery-critical maxima。
same-host isolation 的边界
formal restore 放在 pg-test-3,而 .13 同时继续运行 live replica:
live:
/pg/data
port 5432
Patroni member pg-test-3
isolated:
/data/pg36-ch21-restore/<run>/data
Unix socket only
internal port 55432
no Patroni这是 process/path/network isolation,不是 host/device/failure-domain
isolation,形成 EX21-SHARED-RESTORE-HOST。生产 restore 应使用独立主机。
启动完成不能只看 pg_ctl
pg_ctl -D "$restore/data" -w start可能在只读 consistent state 返回。正式脚本随后:
SELECT pg_is_in_recovery(),
current_setting('transaction_read_only'),
current_setting('archive_mode'),
current_setting('listen_addresses');等待:
recovery=false
transaction_read_only=false
archive_mode=off
listen_addresses=''再做 rollback write。
停止并保留
验证后:
pg_ctl -D "$restore/data" -w -m fast stop检查:
postmaster.pid absent
Unix socket absent
TCP listener absent
restore directory present
live replica still streaming on 5432保留目录支持审计,但不是长期服务。删除由单独 reset:fixture 授权。
防误操作设计
task.sh:
capture|verify|review|all
no mutation
drill:pitr
requires exact target + four nonproduction guards + confirmation
reset:fixture
separate destructive token + exact run IDall 永远不调用 drill:pitr。这避免 CI/读者为了“跑全套检查”意外再做备份
或启动恢复。
版本迁移
迁移到新版本时,工时不只改命令:
review PostgreSQL recovery setting changes
review pgBackRest command options/output schema
review Pigsty variables/playbooks
recreate sanitized baseline
run negative guards
perform fresh restore
compare readiness phases
update exceptions and evidencemigration-effort.json 列出 production
仍需补的 evidence,不把沙箱通过升级为生产。
小结
Pigsty 与 pgBackRest 的价值,是把可恢复性机制交付成一致、可观察、可自动化 的系统。正确使用方式是:
declare with Pigsty
inspect with pgBackRest + PostgreSQL
prove with isolated restore
govern with explicit authority下一节执行完整实验,并逐项解释 formal output、两个安全失败、十四个反例和 生产 gate。
上一节:恢复流程与验证 · 返回本章目录 · 下一节:实战:完成一次隔离恢复演练 · 查看全书目录 · 查看索引中心