# 回写 SLO、SOP 与架构 ADR

LLMS 索引： [llms.txt](/llms.txt)

---

事故揭示的新事实如果只留在 postmortem，日常开发、发布和值班仍会按旧假设运行。
复盘的下游消费者是 SLO、runbook、service catalog、inventory、ADR、测试与版本路线；
每个消费者都需要明确 revision 和 owner。

## 36.5.1 更新观察契约、告警规则与 runbook {#item-36-5-1}

### observation contract 是接口

应用、PostgreSQL、Pigsty 组件和 incident process 对同一 identity 达成约定：

```yaml
service: pg36_shop
revision: obs-v...
identity:
  service: ...
  environment: ...
  pg_cluster: ...
  system_identifier_projection: ...
  instance: ...
  database: ...
  role: ...
  application_name: ...
user_slis:
  availability: ...
  latency: ...
  correctness: ...
diagnostic_sources:
  postgresql_views: [...]
  logs: [...]
  patroni_dcs: [...]
  proxy_pool: [...]
  host_storage: [...]
missing_semantics: ...
retention_and_access: ...
owners: ...
```

新增 label 不是免费：高基数会增加监控成本，敏感 identity 会扩大数据暴露。每个维度
回答“哪项决策需要它”，没有消费者的 telemetry 不应无限保留。

### 从 SLI 到诊断，不从组件告警猜影响

推荐两层告警：

```text
page
  user SLI / error-budget burn / imminent data or recovery risk

ticket or context
  component symptom, capacity trend, maintenance debt
```

例如 replica lag 可能威胁 RPO 或 read-only 用户路径，也可能只是一个无业务 route 的
重建节点。告警需要 topology、route 和 objective 才能分级。Pigsty 的 PostgreSQL、
Patroni、PgBouncer、HAProxy、host、backup 指标可作为诊断层，业务 good-event 仍要由
应用定义。

规则发布前测试：

```text
normal
threshold boundary
fast burn
slow burn
missing series
one instance vs whole service
maintenance and failover
notification routing
```

每条值班告警链接一个能在当前版本执行的 runbook，而不是 dashboard 首页。

### runbook 写判断，不堆命令

```yaml
symptom_or_page: ...
objective: ...
required_identity: ...
first_evidence:
  - source: ...
    why: ...
routes:
  - predicate: ...
    action: ...
    expected: ...
    stop: ...
    rollback: ...
unknown_route:
  action: STOP_AND_ESCALATE
authority: ...
version_scope: ...
last_exercised_at: ...
evidence_example: ...
```

命令输出随 PostgreSQL/Pigsty 版本漂移；runbook 应说明指标和 SQL 的语义，并记录版本
适用范围。危险操作不要留一个通用变量空槽让值班者临时填目标，应从已验证 identity
生成 exact plan 并再次确认。

### 验证回写完成

“文档更新”需要：

1. alert fixture 能进入对应 runbook；
2. 新参与者在 blind tabletop 中请求到正确证据；
3. 错误/缺失 evidence 进入 stop line；
4. 文档链接、query 和权限在当前环境有效；
5. postmortem action 反向链接 observation/runbook revision。

文档过期检测也可自动化：版本、owner、链接、最近演练时间和依赖对象进入 lint。

## 36.5.2 修正 RPO/RTO、容量和安全假设 {#item-36-5-2}

### objective、capability 与 observation 分栏

```text
objective
  业务愿意承诺什么

designed capability
  架构和控制预计支持什么

observed result
  某次真实事件或受控演练测到什么
```

一次 sandbox failover 的 `6,211.692334 ms` acknowledgement gap 是 observation，不是
生产 RTO；一次 fixture PITR 的恢复时间也不包含审批、下载、容量申请、DNS、外部对账
和用户切换。反过来，一个写在文档里的 15 分钟 RTO 若从未演练，也不是 capability。

### RPO 不是一个数据库数字

按结果类型拆分：

```text
database transaction durability
replica / WAL archive lag
backup recovery point
business event and outbox state
external side effect
audit/reconciliation source
```

异步复制、archive 与 backup 各有不同 loss window。PITR 到正确 target 仍可能丢弃
target 后的合法写；数据库恢复也不会自动撤销已发出的支付、邮件或消息。因此 RPO
合同写数据类别、cutoff、source、对账方法和 exception。

### RTO 分解而不是报一个 stopwatch

$$
\mathrm{RTO} =
T_{\mathrm{detect}} +
T_{\mathrm{decide}} +
T_{\mathrm{provision}} +
T_{\mathrm{restore}} +
T_{\mathrm{validate}} +
T_{\mathrm{route}} +
T_{\mathrm{observe}}
$$

不同路线各自分布：

- automatic/controlled failover；
- PITR candidate + reconciliation；
- replica rebuild；
- backup restore；
- data extraction/forensic recovery；
- host/region rebuild。

记录 p50/p95 并不代表数据足够；小样本保留 raw runs 和条件。把最慢、最不确定且可改变
的阶段转成行动，而不是只优化 PostgreSQL copy speed。

### 容量与安全假设也要版本化

事故后检查 ADR 中的隐含假设：

```text
peak and retry multiplier
pool/session/work_mem concurrency
WAL/archive/slot growth rate
vacuum/freeze window
backup repository and restore bandwidth
DCS/failure-domain independence
credential and network trust boundary
break-glass availability and audit
monitoring dependency during control-plane failure
```

每项写 evidence、margin、owner、invalidation event。将“单节点也够用”“replica 一定
最新”“内网可信”“备份每天成功”这种自然语言替换为可测谓词。

### 不因事故随意降低目标

若观测证明 objective 不可实现，有三个诚实选择：

1. 投资能力达到业务目标；
2. 调整产品/降级设计，缩小承诺范围；
3. 与业务共同接受并批准新目标和 residual risk。

不能为了让报表变绿而单方面降低 SLO/RPO/RTO，也不能保留不可能实现的目标让值班者
承担结构性失败。

## 36.5.3 将必要变更纳入服务目录与版本路线 {#item-36-5-3}

### service catalog 是事故路由表

数据库服务条目至少包含：

```yaml
service_and_tier:
business_owner:
technical_owner:
oncall_and_escalation:
data_classification:
postgresql:
  cluster:
  major_and_extensions:
  databases:
  writer_and_reader_services:
pigsty:
  inventory_revision:
  release:
dependencies:
  dcs:
  backup_repository:
  object_storage:
  identity_and_secrets:
objectives:
  sli_slo:
  rpo_rto:
controls:
  backup_restore:
  ha_fencing:
  capacity:
  integrity:
  security:
last_verified:
exceptions:
```

这不是手工 CMDB 展示页。inventory 和 runtime 能自动投影的字段不重复录入；业务
owner、data class、objective、外部 dependency 与例外仍需显式治理。

### 用 ADR 记录为什么

配置告诉系统“是什么”，ADR 解释“为什么这样、在什么条件下仍正确”：

```markdown
# ADR-...: ...

Status / Date / Owners
Context and incident evidence
Decision
Alternatives considered
Assumptions and version scope
Consequences and new failure modes
Migration / rollback
Verification and observability
Invalidation / review trigger
Related controls and postmortems
```

例如把 DCS 从单故障域扩为多成员，不能只写节点数；ADR 要讨论 failure domain、quorum、
latency、failsafe/watchdog、maintenance、network partition 和运营复杂度。

### 版本路线按风险依赖排序

行动可能需要：

- PostgreSQL minor/major fix；
- Pigsty/Patroni/pgBackRest/PgBouncer/HAProxy 版本更新；
- extension compatibility 与 `shared_preload_libraries`；
- OS、kernel、filesystem、ICU/libc 或 hardware firmware；
- dashboard/alert/runbook schema；
- 应用 driver、retry、transaction 和 idempotency contract。

建立 compatibility matrix：

```text
current -> candidate
known incident relevance
support/security window
configuration semantic diff
extension and backup compatibility
rollback boundary
staged evidence
production approval
```

不要把多个必要升级捆成一次无法归因的大爆炸。先解决阻塞链和可观测性，再 canary/
batch；每阶段都有 before/after、stop 和 rollback。

### Pigsty 映射

Pigsty 的声明式 inventory 与幂等 playbook 适合承载 desired state；监控栈适合承载
control telemetry；pgBackRest、Patroni、PgBouncer 和 HAProxy 分别承载恢复、权威、
连接与路由机制。但平台不会替业务定义：

```text
good user event
transaction and idempotency boundary
acceptable data loss
business invariant
external side-effect reconciliation
```

这些应用合同必须回写 service catalog，并与 Pigsty/PostgreSQL 证据在同一次演练中
共同验收。

### 路线变更也需要退出条件

每个 roadmap item 记录：

```text
why now
dependency and owner
target version/revision
evidence before rollout
success and stop criteria
rollback support window
when old path is retired
```

只有当旧例外、旧 runbook、旧 dashboard 和旧配置都被清点，版本演进才真正关闭；
否则值班时仍可能按过时入口执行。

---

[上一节：把行动项变成控制](../04/) · [返回本章目录](../) · [下一节：将控制固化到平台](../06/) ·
[查看全书目录](/toc/) · [查看索引中心](/indexes/)
