跳至内容

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、风险、补偿控制和到期日

从外向内、逐项回收

推荐次序随事故调整,但每次只改变一个可解释变量:

  1. 确认稳定基线与 rollback;
  2. 回收过期的 break-glass 权限、token 和会话;
  3. 恢复被暂停的监控、归档、备份、vacuum 与调度;
  4. 校正路由和服务发现,移除旁路;
  5. 分阶段撤销限流或降级,观察 user SLI 与资源余量;
  6. 恢复常规变更窗口;
  7. 验证 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: true

postmortem_trigger_decided 不等于“复盘已经写完”。达到上面条件后,事件可以从实时 响应转入学习与控制工作;后续三种状态分别追踪:

incident: closed
postmortem: draft -> reviewed -> published
actions: proposed -> implemented -> effectiveness-verified -> expired/revalidated

这能避免为了让 dashboard 上的 incident 数量归零,而提前把未验证行动标成完成。


返回本章目录 · 下一节:从时间线建立因果链 · 查看全书目录 · 查看索引中心

最后更新于