34.6 保留型故障的安全路由
保留型事故的第一原则是:
先证明“谁还需要哪段历史”,再决定是恢复消费者、迁移恢复来源,还是释放这项需要。
一条复制槽、一个 xmin 或一批 WAL 文件本身不是垃圾。它们是恢复、复制、快照或事务 协议的状态。未经 owner 与恢复链确认的“清理”,可能把空间问题变成不可恢复的数据 问题。
34.6.1 XID:检查 backend_xmin、复制槽 xmin 与 pg_prepared_xacts
先列出所有可能的 horizon owner
活动 backend:
SELECT pid,
datname,
usename,
application_name,
state,
xact_start,
backend_xid,
backend_xmin,
wait_event_type,
wait_event
FROM pg_stat_activity
WHERE backend_xid IS NOT NULL
OR backend_xmin IS NOT NULL
ORDER BY xact_start NULLS LAST;复制槽:
SELECT slot_name,
slot_type,
database,
active,
xmin,
catalog_xmin,
restart_lsn,
inactive_since,
invalidation_reason
FROM pg_replication_slots
ORDER BY slot_name;两阶段事务:
SELECT transaction,
gid,
prepared,
owner,
database
FROM pg_prepared_xacts
ORDER BY prepared;再看 database/relation freeze age:
SELECT datname,
age(datfrozenxid) AS xid_age,
mxid_age(datminmxid) AS multixact_age
FROM pg_database
ORDER BY xid_age DESC;这些视图回答的是不同问题:
backend_xmin:该 backend 当前快照仍可能看到多老的版本;- slot
xmin:消费者需要的数据行版本边界; catalog_xmin:逻辑解码需要的 catalog 版本边界;- prepared XID:已经
PREPARE TRANSACTION、等待外部决议的事务; datfrozenxid:数据库中尚未冻结事务的保守下界。
不要把最老 PID 自动当成罪魁
一个长 session 未必持有 xmin;一个短暂但 prepared 的事务可能没有 session 却长期
持锁。logical slot 的 catalog_xmin 也可能成为 catalog vacuum 的约束。先把每个边界
映射到:
owner
business or replication purpose
last successful progress
expected outage/retention window
recoverability if released
approved decision maker处置路线:
| 保留者 | 安全路线 |
|---|---|
| 应用长事务 | 联系 owner,停止新工作,评估 cancel/terminate 与补偿 |
| prepared transaction | 与 transaction manager/ledger 对账后 commit 或 rollback |
| logical slot | 恢复 consumer,或从新起点重建并明确数据缺口 |
| freeze 落后 | 修复 blocker/资源后执行受控 vacuum/freeze |
| 无法识别 | 保持证据,升级,不释放 |
完整的 XID、freeze 与膨胀处理见第 28 章。
34.6.2 WAL 撑盘:检查归档失败、复制槽和未完成备份
pg_wal 大小不是根因
WAL 目录可以因为正常高写入暂时变大,也可以因为保留者不推进持续增长。先记录:
SELECT pg_current_wal_lsn() AS current_lsn,
pg_wal_lsn_diff(
pg_current_wal_lsn(),
'0/0'::pg_lsn
) AS absolute_lsn_bytes;
SELECT slot_name,
slot_type,
active,
restart_lsn,
pg_wal_lsn_diff(
pg_current_wal_lsn(),
restart_lsn
) AS retained_wal_bytes,
wal_status,
safe_wal_size,
invalidation_reason
FROM pg_replication_slots
ORDER BY retained_wal_bytes DESC NULLS LAST;
SELECT archived_count,
failed_count,
last_archived_wal,
last_archived_time,
last_failed_wal,
last_failed_time
FROM pg_stat_archiver;同时检查:
physical replica receive/replay progress
logical consumer confirmed progress
archive command/repository health
base backup / restore / WAL summarization activity
checkpoint timing
WAL generation rate by workload
filesystem free bytes and inode headroompg_stat_archiver.failed_count 是累计量;单次历史失败不证明当前仍坏。需要看最近成功、
最近失败和时间窗增量。slot active=true 也只说明当前有人连接,不说明 restart_lsn
正在推进。
未完成备份也是恢复链的一部分
备份过程可能需要一段 WAL 才能形成一致恢复点。事故中贸然停止备份、删除 staging 或释放 WAL,可能让本来可用的恢复副本失效。记录:
backup run id / start LSN / stop LSN
repository and archive confirmation
base backup progress
restore validation state
current RPO source
alternative healthy backup/replica若空间即将耗尽,可以同时减少非关键写入,降低 WAL 增长率;这只是争取时间,不是 修复 retention owner。
slot 的有限上限也不是无损方案
max_slot_wal_keep_size 可以限制 checkpoint 时允许 replication slot 保留的 WAL;
超过可用范围时 slot 可能不再可继续使用,wal_status/invalidation_reason 会反映
状态。它是防止磁盘无限增长的风险取舍,不保证 consumer 无损恢复。配置前必须明确:
consumer maximum outage
WAL generation envelope
alert lead time
reseed procedure
accepted data-loss semantics34.6.3 绝不手工删除 pg_wal;保护现场后转 ch21/ch28/ch35
为什么文件看起来“旧”也不能删
PostgreSQL 自己依据 checkpoint、recovery、归档和复制需要管理 WAL segment。文件名
顺序不能告诉操作者某段是否仍被 crash recovery、standby、backup 或 timeline history
需要。运行中用 rm 删除 pg_wal:
- 不会更新 control/catalog/slot 状态;
- 可能让当前实例在 crash recovery 时缺日志;
- 可能让 replica、PITR 或 backup 无法继续;
- 会破坏最重要的事故证据;
- 当前进程暂时继续运行,也不能证明下次 restart 可恢复。
正确做法是:
reduce noncritical WAL generation
preserve SQL + filesystem + archive evidence
identify exact retention owner
repair archive/consumer or establish a new recovery source
release only an exact, authorized object through PostgreSQL
verify recovery chain and filesystem headroom路由到正确章节
- XID、vacuum、freeze、膨胀:转第 28 章;
- 归档、备份、恢复链:转第 21 章;
- 已发生文件缺失、checksum/页/索引异常:保护现场,转 第 35 章;
- 错删/误写但物理集群健康、需要时间点恢复:结合 第 32 章。
每次转交都带:
facts:
system_identifier_timeline: ...
current_and_retained_lsn: ...
owner_consumer: ...
archive_backup_state: ...
growth_rate_time_to_full: ...
actions_already_taken: [...]
unknowns: [...]
forbidden_actions:
- manual delete pg_wal
- drop unknown slot34.6.4 本章的一般止血动作不构成保留型修复
常见伪修复
| 动作 | 可能短期效果 | 为什么没修复保留边界 |
|---|---|---|
| cancel 普通慢查询 | 降低 CPU/I/O | 不一定命中持 xmin 的事务 |
| 限制新连接 | 减少 flow | slot/归档边界仍不推进 |
| 增加磁盘 | 延后满盘 | owner 与恢复链仍旧失效 |
| 重启数据库 | 清部分 session | prepared xact/slot/归档问题仍在,且增加恢复风险 |
| drop 所有 inactive slot | 快速释放 WAL | 破坏未知 consumer 的恢复能力 |
| 删除 WAL 文件 | 目录变小 | 数据库状态未修复,恢复链被破坏 |
增加磁盘在硬故障逼近时可以是合法的时间购买动作,但报告必须写:
temporary headroom gained
new estimated time to full
retention owner unchanged
permanent repair owner/deadline
rollback or capacity reconciliation保留型成功标准
不是“磁盘百分比下降”,而是:
exact retention owner identified
oldest required horizon is advancing or deliberately re-established
consumer/archive/backup has a valid recovery path
released capability and accepted loss are recorded
WAL/XID growth rate returns inside envelope
replicas and PITR validation pass
temporary storage/traffic controls are reconciled如果唯一能说的是“删完之后 PostgreSQL 还在运行”,事故尚未被安全恢复。
上一节:流量型止血动作 · 返回本章目录 · 下一节:平台级流量控制与证据 · 查看全书目录 · 查看索引中心