select historical lineage
-> copy base
-> replay WAL
-> stop at boundary
-> possibly promote onto new timeline
-> decide what may consume this history
每一步都可能生成一个能启动、却不应交付的实例。因此流程必须先写停止条件,
再写命令。
21.4.1 选择备份集、目标时间和恢复位置
先冻结事故事实
开始恢复前,保留:
incident start and detection time in UTC
suspected destructive transaction/request
source cluster identity and current timeline
current repository catalog
archive maximum and gaps
relevant application/audit logs
last known correct business marker
authority and requested outcome
kind:namevalue:before_release_20260729inclusive:not-applicabletimezone:UTCsource_evidence:- pg_create_restore_point result- release change recordexpected:present:- schema version 41- business token Aabsent:- migration transaction Bapproved_by:- incident commander- data owner
时间 target 应包含 offset:
2026-07-29 20:10:44.000+00
避免依赖 session/local timezone。
target 类型选择
known pre-created boundary
name
known destructive transaction
xid + inclusive=false, after verifying identity
known physical log point
lsn
only trusted event time
time + explicit timezone/inclusive
need earliest consistent database
immediate
need latest independently archived state
end of archive, with RPO evidence
finish before or otherwise be valid for target
belong to same physical lineage
have all dependent backup objects
have continuous required WAL to target
have reachable timeline history
have usable encryption key
fit target runtime/version
对 time target,pgBackRest 可以选择一份结束时间早于 target 的可用 backup。
对 name/XID,工具不能总是自动知道 target 落在哪份历史中;pgBackRest
User Guide 明确提示 name/XID target 无法自动选择 backup。正式 run 因此用
--set=<exact-label> 固定刚创建的 full。
“最新备份”可能太新
误删发生在 10:00:
backup A ends 09:00
backup B starts 11:00
选择 B 无法回到 10:00 之前,因为其文件状态已经包含误删;需要 A 加 WAL。
“latest”不是无条件正确。
backup set 与 recovery target 分离
--set
chooses base/dependency set
--type / --target
chooses where WAL replay stops
一个是起点,一个是终点。混淆会导致:
起点晚于目标;
自动选择错误;
恢复到 WAL 尾部而不是事故前;
以为 backup label 就是业务时刻。
恢复位置
优先顺序:
new host/failure domain
best isolation
same host, new path/process/socket/port
useful lab compromise with explicit exception
overwrite original data directory
destructive replacement only, separate authority
read-only catalog/capture
no database or repository mutation
isolated restore drill
synthetic source writes + new backup/path/postmaster
production replacement/cutover
stops/overwrites/reroutes real service
本章 formal 只有第二种沙箱授权。不能拿它的确认 token 去生产。
21.4.2 启动前核对时间线与 WAL 完整性
preflight 清单
在 postgres 启动前确认:
exact source/stanza/system lineage
exact backup label and type
backup status and dependency completeness
backup start/stop WAL
target kind/value/inclusive
target WAL covered by archive
timeline history available
restore_command configured
recovery.signal present
standby.signal absent unless desired
tablespace path and ownership
PostgreSQL major/binaries/extensions
recovery-critical max settings
network/HBA/archive isolation
log destination writable
把它写入 evidence,不要只在人的终端滚过。
repository catalog
pgBackRest:
sudo -iu postgres \
pgbackrest --stanza=pg-test --repo=1 --output=json info
检查:
stanza status code
database/repository id
PostgreSQL version
backup label/type/error
start/stop timestamp
start/stop archive
logical/repository bytes
archive min/max by archive id
locks
不要把输出中的 repository secret 或 raw system identifier 复制进公开 evidence。
stop
read PostgreSQL FATAL/DETAIL/HINT
compare with captured source settings
correct isolated runtime
start as a new reviewed attempt
never weaken source or edit WAL/control data
extension 与 preload
物理 backup catalog 可能引用 extension。恢复环境若缺 .so:
startup 可能因 shared_preload_libraries 失败;
查询对象可能缺函数/type;
background worker 可能连接外部系统。
验证实例需要决定:
install exact extension packages
or explicitly disable reviewed preload components
no Patroni process
no DCS registration
no HAProxy service
no exporter discovery
no archive push
如果目标是正式替换 cluster,加入平台是另一个经过审查的阶段。
日志是证据
关注顺序:
starting backup recovery
restored history/WAL from archive
starting point-in-time recovery to ...
redo starts
consistent recovery state reached
ready to accept read-only connections
recovery stopping at target
selected new timeline
archive recovery complete
end-of-recovery checkpoint
ready to accept connections
错误:
requested WAL not found
recovery ended before configured target
invalid checkpoint record
insufficient parameter settings
could not load library
tablespace path failure
permission denied
不要只保存最后一行 database system is ready。
两阶段 readiness
正式 runner:
用 pg_ctl -w 等到第一条连接;
立即记录 pg_is_in_recovery() 与 transaction_read_only;
继续轮询到 recovery=false;
查询 effective isolation;
做 rollback-only write;
才声明 promotion complete。
观测:
first connection:
in_recovery=true
transaction_read_only=true
355.896 ms later:
in_recovery=false
transaction_read_only=false
这不是理论角落,而是本章真实运行结果。
21.4.3 数据库一致不等于业务数据正确
引擎一致性
PostgreSQL recovery complete 能说明:
WAL record 可重放到一致点;
control/catalog/transaction state 满足引擎;
数据库可按当前模式接受连接;
promotion 时建立了新 timeline。
不能说明:
target 是事故前正确边界;
所有正确交易都在;
错误交易都不在;
外部系统一致;
应用 schema/code 匹配;
秘密与权限适合交付;
报表金额正确。
业务不变量
为每个服务维护可执行 invariant:
orders
no orphan order lines
order total = sum(lines)
accepted payment token unique
known checkpoint token present
destructive release token absent
ledger
debits = credits per journal
immutable entries not missing
sequence/event continuity
tenant SaaS
no row crosses tenant boundary
tenant counts match reference
row-level security policies installed