36.1 服务恢复不等于事件结束
SELECT 1 成功、主端点重新可连或 Grafana 曲线回落,只能说明某个观察面在某一时刻
恢复。事件是否结束,还取决于用户结果、数据正确性、恢复能力、容量余量和临时控制
是否都回到可接受状态。
36.1.1 恢复用户影响、数据正确性与运行余量
用状态向量代替单点绿灯
事件恢复状态可以写成:
$$ R = (U, D, H, P, O) $$
其中:
U user outcome:成功率、延迟、功能和影响人群
D data:完整性、一致性、unknown outcome 与外部副作用
H headroom:连接、CPU、内存、I/O、WAL、XID、容量余量
P protection:HA、backup/archive、权限、围栏和回退能力
O operations:监控、告警、自动化、值班和变更路径只有各维都达到预先定义的 acceptance,才能从 active incident 进入观察。典型的反例:
| 表面恢复 | 尚未回答 |
|---|---|
| 应用成功率回升 | 超时请求究竟提交还是回滚 |
| 新主库可写 | 旧主是否已围栏、replica 是否同 lineage |
| 磁盘空间释放 | slot/XID owner 是否恢复、WAL archive 是否连续 |
| PostgreSQL 启动 | checksum、索引、业务不变量是否可信 |
| PITR candidate 可查询 | target 是否正确、合法 post-target 写是否对账 |
用户影响要从用户路径测量。数据库连接成功不是订单可提交,readiness probe 成功也不是 支付状态正确。至少比较 incident 前基线、影响窗口和恢复窗口:
user_journey: checkout_commit
sli_revision: checkout-v4
window:
impact_start: ...
mitigation_start: ...
observation_end: ...
segments:
region: [...]
client_version: [...]
operation: [...]
result:
attempts: ...
good: ...
unknown: ...
duplicate: ...
source_query_hash: ...unknown 不能并入 success 或 failure;它需要 stable request token、业务 ledger、
outbox/inbox 和外部系统对账。
正确性恢复要写明 cutoff
“数据已经恢复”至少需要:
accepted source and system identifier/timeline
restore or reconciliation cutoff
confirmed affected object and row/event scope
versioned business invariant
external side-effect reconciliation
unrecoverable and still-unknown register
owner acceptance验证查询本身也可能因 snapshot、时区、collation、replica lag 或遗漏 partition 而说谎。 保存 SQL/程序 hash、参数、执行角色、目标 endpoint 和 snapshot/cutoff。抽样可用于 早期判断,不能自动替代最终全量或风险加权验收。
运行余量是恢复的一部分
若服务只在当前流量下勉强稳定,下一次重试、checkpoint、autovacuum 或 backup 就可能 再次触发事故。对每个主要资源记录:
$$ \text{headroom} = \frac{\text{safe capacity} - \text{current demand}} {\text{safe capacity}} $$
safe capacity 来自压测与安全边界,不等同于理论最大值。观察:
- active/queued connection 与 pool wait;
- CPU run queue、memory pressure、swap/OOM 和 I/O latency;
- WAL generation/archive/retention 与 filesystem free;
- replica replay lag、slot restart LSN 与 backup freshness;
- oldest xmin、freeze age、dead tuples 与 maintenance debt;
- error budget burn、retry amplification 和降级队列积压。
事故后的补偿、缓存回暖、索引重建和备份会制造第二波负载;应纳入容量计划。
36.1.2 清理临时降级、应急权限和旁路配置
为每个临时动作建债务账本
incident commander 批准临时动作时就应同步登记回收条件:
temporary_control_id: TC-...
target_identity: ...
change:
desired_before: ...
emergency_value: ...
reason: ...
owner_role: ...
approved_at: ...
expected_effect: ...
stop_condition: ...
rollback_or_supersede: ...
expires_at: ...
verification_after_removal: ...常见临时债务:
- 只读、限流、功能开关、缩短队列或拒绝非关键工作;
- 精确暂停 failover、backup、vacuum、发布或调度器;
- 临时路由、旁路 endpoint、DNS/HAProxy 权重;
- break-glass role、临时证书、放宽的网络来源;
- 提高日志、采样或 trace 密度;
- 临时增加资源、保留 replication slot 或 forensic clone;
- 为抽取损坏数据而只在 clone 使用的危险参数。
不要在压力刚回落时机械执行“全部 revert”。临时限流可能仍在保护低余量系统,立即 撤掉会重启事故。先确认它是:
remove now
原风险消失,移除不会突破余量
replace with permanent control
临时动作有效,但实现、权限或可观测性不适合长期保留
retain with dated exception
当前不能移除,有 owner、风险、补偿控制和到期日从外向内、逐项回收
推荐次序随事故调整,但每次只改变一个可解释变量:
- 确认稳定基线与 rollback;
- 回收过期的 break-glass 权限、token 和会话;
- 恢复被暂停的监控、归档、备份、vacuum 与调度;
- 校正路由和服务发现,移除旁路;
- 分阶段撤销限流或降级,观察 user SLI 与资源余量;
- 恢复常规变更窗口;
- 验证 inventory、runtime 和 secrets source 没有漂移。
安全相关临时措施按“先建立替代保护,再移除旧保护”处理。不要为关闭 incident 而 先删证据 clone、storage snapshot、audit log 或 recovery backup;它们按证据保留 策略单独到期。
Pigsty 中比较 desired 与 observed
Pigsty inventory 描述期望集群、实例、服务、用户、数据库和参数;运行中的 PostgreSQL、 Patroni、HAProxy、PgBouncer 与监控则提供 observed state。事故后至少做三方对照:
version-controlled inventory
vs rendered configuration
vs runtime/catalog/topology observation差异要么回写声明式配置并评审,要么从 runtime 清除。不要只修改现场,留下下一次
playbook 重跑会覆盖的“幽灵修复”;也不要未经 diff 把 inventory 全量重放到刚恢复的
系统。危险 playbook 使用 exact -l 目标、safeguard、preview 和独立批准。
36.1.3 通知、观察窗口与正式结案条件
恢复通知要说已知、未知和下一步
一次可信的恢复更新包含:
current user impact and affected segments
confirmed impact window
mitigation/recovery performed
data correctness and unknown-outcome status
temporary controls still active
what remains unverified
observation window and next update
owner/contact and escalation path不要使用“完全恢复”“无数据丢失”这类超出证据的表述。如果结论只覆盖 fixture、区域、 时间 cutoff 或某类业务对象,就明确写出量词。安全、隐私、法律和客户通知由相应 owner 决策,工程团队提供事实、范围与置信度,不自行淡化或扩大。
观察窗口由失效周期决定
“观察 30 分钟”不是通用规则。窗口至少覆盖相关周期:
- 高峰流量、重试和 backlog 排空;
- checkpoint、WAL switch、archive 与 backup;
- autovacuum/freeze 或维护任务;
- replica catch-up、connection recycle、DNS/TTL;
- cache warm-up、batch、settlement 或账务周期;
- 临时控制撤销后的再暴露。
有些验证必须经过一个完整 backup + restore 或下一次业务结算,不能让 active incident 无限挂起;可以将事件关闭,同时把长期验证转成有 owner 的 control action。但交接 不能抹掉风险。
结案门
incident_closure:
user_sli_accepted: true
business_invariants_accepted: true
unknown_outcomes_reconciled_or_owned: true
capacity_headroom_accepted: true
ha_backup_archive_monitoring_restored: true
temporary_controls_accounted_for: true
evidence_retention_recorded: true
stakeholder_update_sent: true
observation_window_passed: true
residual_risks_owned: true
postmortem_trigger_decided: truepostmortem_trigger_decided 不等于“复盘已经写完”。达到上面条件后,事件可以从实时
响应转入学习与控制工作;后续三种状态分别追踪:
incident: closed
postmortem: draft -> reviewed -> published
actions: proposed -> implemented -> effectiveness-verified -> expired/revalidated这能避免为了让 dashboard 上的 incident 数量归零,而提前把未验证行动标成完成。
返回本章目录 · 下一节:从时间线建立因果链 · 查看全书目录 · 查看索引中心