跳至内容
21.5 用 pgBackRest 交付备份策略

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 observability

21.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_secretcipher_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-compatibleobject 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 info

Pigsty 在启用备份组件时交付配置/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 dependency

JSON 仍可能含 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 breaches

backup 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_wal

repository:

used bytes
object count
growth forecast
version/lock overhead
cold tier
retention expiry

restore 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。

观察矩阵

信号warningcritical/action
latest full age接近 policy越过恢复合同
archive max lag上升RPO 越线/磁盘风险
pg_wal freeforecast shrink可能 PANIC
repository freeforecast shrink下一备份不可完成
backup durationtrend regressionwindow/RTO risk
failed count deltanew failureinspect/retry
restore drill age接近周期recoverability unproven
key expiryrotation windowfuture 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,以及 exclusiverecovery_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 directory

Pigsty 提供配置、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 ID

all 永远不调用 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 evidence

migration-effort.json 列出 production 仍需补的 evidence,不把沙箱通过升级为生产。

小结

Pigsty 与 pgBackRest 的价值,是把可恢复性机制交付成一致、可观察、可自动化 的系统。正确使用方式是:

declare with Pigsty
inspect with pgBackRest + PostgreSQL
prove with isolated restore
govern with explicit authority

下一节执行完整实验,并逐项解释 formal output、两个安全失败、十四个反例和 生产 gate。


上一节:恢复流程与验证 · 返回本章目录 · 下一节:实战:完成一次隔离恢复演练 · 查看全书目录 · 查看索引中心

最后更新于