事故复盘、控制固化与平台演进——举一反三
36 事故复盘、控制固化与平台演进——举一反三
服务恢复解决的是“现在还能不能用”,事故复盘要解决的是“为什么系统允许这条失效链 成立,以及下一次什么会不同”。如果复盘止于一份文档,系统没有发生任何变化;如果 行动止于“代码已经合并”,控制也未必真的有效。
本章把全书最后一个闭环写成:
“无责”不是“无因”或“无责任”。它要求不把复杂系统失败压缩成人格评价,同时仍精确 记录谁以什么 role 对哪项控制、截止时间和验证证据负责。
学习完成标准
完成本章后,读者应能:
- 分开用户影响恢复、数据正确性、运行余量与 incident closure;
- 清点并回收临时降级、应急权限、路由旁路和被暂停的自动化;
- 为通知、观察窗口、证据保留和正式结案定义可验证条件;
- 用事件时间、采集时间和知识时间重建 append-only timeline;
- 区分 trigger、放大机制、failed defense 与潜在失效条件;
- 从技术、流程、组织和认知四个层面寻找 contributing factors;
- 写出不归罪个人、又不回避具体动作与决策缺陷的复盘;
- 区分当时可见事实、当时假设、后来证据与事后解释;
- 判断某个正确结果来自受控机制,还是仅仅来自运气;
- 评估日志、指标、trace、审计、时间同步和 retention 的证据质量;
- 把行动项写成 owner role、期限、控制类型、验证、失效与重验合同;
- 区分 prevent、detect、mitigate、recover 四类控制;
- 拒绝“加强意识”“以后注意”和“部署即关闭”等不可验收行动;
- 把教训回写到 SLI/SLO、runbook、恢复目标、安全假设和 ADR;
- 用 Pigsty inventory、模板、监控规则、safeguard 与演练承载平台控制;
- 将局部补丁升级为默认护栏,同时保留 exception、版本和退出路径;
- 从多个事故识别重复控制主题,但不把教学实验冒充生产缺陷;
- 产出 90 天路线,并用独立证据而不是 ticket 状态关闭控制。
三种关闭不能混为一谈
| 层次 | 关闭条件 | 不能替代它的信号 |
|---|---|---|
| incident | 用户影响、正确性、容量余量与运行路径稳定 | endpoint 偶尔返回 200 |
| postmortem | 影响、时间线、因果、决策、未知项经相关方评审 | 文档创建成功 |
| control action | 指定验证通过,关闭证据被独立接受,重验时间已登记 | PR merged / ticket done |
行动关闭后,控制还可能因版本、流量、拓扑、人员边界或依赖变化而失效。因此控制注册表
需要 last_verified_at、evidence、valid_until 或 revalidation_days,而不是
永久绿色的 checkbox。
从四类演练提取控制主题
第 32~35 章分别保留了四条恢复路线:
| 章节 | 场景 | 主要决策 | 不能外推 |
|---|---|---|---|
| ch32 | 误写与 PITR | 排除错误 history,合并审计后的合法增量 | sandbox timing 不是生产 RTO |
| ch33 | 主库失效 | 围栏、接纳新权威、对账 unknown、修复 lineage | 受控停进程不是硬件/网络分区 |
| ch34 | flow 与 retention pressure | 先分类,再限流或修复 owner | fixture 阈值不是生产容量线 |
| ch35 | 物理与派生损坏 | 从可信源恢复或重建 derived state | 单字节/元数据注入不是真实介质故障 |
它们反复提示 observation contract、生产门禁、业务验收、精确作用域、unknown outcome、 未知分类停止线和 lineage/authority 七个主题。这里的措辞必须严格:
只有生产 inventory、流程、配置和演练证据完成评估后,某个主题才能被确认成实际缺口。
正式实验
本章的实验是完全离线的 postmortem compiler。它读取四份已冻结、去敏的公开摘要:
每个 observed fact 都绑定 source JSON Pointer、expected value、actual value 和 knowledge stage。编译器产出四份事故记录、七个跨事故控制主题、十二项 0~90 天参考 backlog 和覆盖 ch01~ch36 的能力评估合同。
正式 run 91c4464b-89f7-4145-9708-f07256d747ce:
36 个 live mutant 包括篡改源事实、把 sandbox 影响冒充真实用户、删除 action owner、
期限、验证或失效条件、自动批准生产动作、漏掉路线阶段,以及仅因能力地图完整就自动
认证读者。公开结果见 closure-run.json。
本章边界
本章没有:
- 分析任何真实生产事故、个人或客户数据;
- 证明读者所在组织存在七个缺口;
- 创建工单、发送通知、修改 Pigsty inventory 或执行 backlog;
- 把第 32~35 章一次实验计时提升成 SLO/RTO;
- 因为读者完成阅读而自动授予能力认证。
正式结论保持:
阅读前后关系
本章目录
36.1 服务恢复不等于事件结束
36.2 从时间线建立因果链
36.3 证据质量与决策复盘
36.4 把行动项变成控制
36.5 回写 SLO、SOP 与架构 ADR
36.6 将控制固化到平台
36.7 实战:复盘四类事故并完成全书结业
- 36.7.1 汇总 ch32–ch35 的证据、决策与用户影响
- 36.7.2 找出跨事故重复出现的控制缺口
- 36.7.3 输出 90 天改进路线、平台 backlog 与复验计划
- 36.7.4 回看从 SQL 到生产的能力地图
权威参考
复盘与 SRE:
- Google SRE Book: Postmortem Culture
- Google SRE Workbook: Postmortem Culture
- Google SRE Workbook: Monitoring
- Google SRE Workbook: Alerting on SLOs
PostgreSQL:
Pigsty:
上一章:数据抢救与工程取证——起死回生 · 返回下卷导读 · 返回全书导读 · 查看全书目录 · 查看索引中心
36.1 服务恢复不等于事件结束
SELECT 1 成功、主端点重新可连或 Grafana 曲线回落,只能说明某个观察面在某一时刻
恢复。事件是否结束,还取决于用户结果、数据正确性、恢复能力、容量余量和临时控制
是否都回到可接受状态。
36.1.1 恢复用户影响、数据正确性与运行余量
用状态向量代替单点绿灯
事件恢复状态可以写成:
其中:
只有各维都达到预先定义的 acceptance,才能从 active incident 进入观察。典型的反例:
| 表面恢复 | 尚未回答 |
|---|---|
| 应用成功率回升 | 超时请求究竟提交还是回滚 |
| 新主库可写 | 旧主是否已围栏、replica 是否同 lineage |
| 磁盘空间释放 | slot/XID owner 是否恢复、WAL archive 是否连续 |
| PostgreSQL 启动 | checksum、索引、业务不变量是否可信 |
| PITR candidate 可查询 | target 是否正确、合法 post-target 写是否对账 |
用户影响要从用户路径测量。数据库连接成功不是订单可提交,readiness probe 成功也不是 支付状态正确。至少比较 incident 前基线、影响窗口和恢复窗口:
unknown 不能并入 success 或 failure;它需要 stable request token、业务 ledger、
outbox/inbox 和外部系统对账。
正确性恢复要写明 cutoff
“数据已经恢复”至少需要:
验证查询本身也可能因 snapshot、时区、collation、replica lag 或遗漏 partition 而说谎。 保存 SQL/程序 hash、参数、执行角色、目标 endpoint 和 snapshot/cutoff。抽样可用于 早期判断,不能自动替代最终全量或风险加权验收。
运行余量是恢复的一部分
若服务只在当前流量下勉强稳定,下一次重试、checkpoint、autovacuum 或 backup 就可能 再次触发事故。对每个主要资源记录:
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 批准临时动作时就应同步登记回收条件:
常见临时债务:
- 只读、限流、功能开关、缩短队列或拒绝非关键工作;
- 精确暂停 failover、backup、vacuum、发布或调度器;
- 临时路由、旁路 endpoint、DNS/HAProxy 权重;
- break-glass role、临时证书、放宽的网络来源;
- 提高日志、采样或 trace 密度;
- 临时增加资源、保留 replication slot 或 forensic clone;
- 为抽取损坏数据而只在 clone 使用的危险参数。
不要在压力刚回落时机械执行“全部 revert”。临时限流可能仍在保护低余量系统,立即 撤掉会重启事故。先确认它是:
从外向内、逐项回收
推荐次序随事故调整,但每次只改变一个可解释变量:
- 确认稳定基线与 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。事故后至少做三方对照:
差异要么回写声明式配置并评审,要么从 runtime 清除。不要只修改现场,留下下一次
playbook 重跑会覆盖的“幽灵修复”;也不要未经 diff 把 inventory 全量重放到刚恢复的
系统。危险 playbook 使用 exact -l 目标、safeguard、preview 和独立批准。
36.1.3 通知、观察窗口与正式结案条件
恢复通知要说已知、未知和下一步
一次可信的恢复更新包含:
不要使用“完全恢复”“无数据丢失”这类超出证据的表述。如果结论只覆盖 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。但交接 不能抹掉风险。
结案门
postmortem_trigger_decided 不等于“复盘已经写完”。达到上面条件后,事件可以从实时
响应转入学习与控制工作;后续三种状态分别追踪:
这能避免为了让 dashboard 上的 incident 数量归零,而提前把未验证行动标成完成。
返回本章目录 · 下一节:从时间线建立因果链 · 查看全书目录 · 查看索引中心
36.2 从时间线建立因果链
时间线回答“先后发生了什么”,因果分析回答“哪些条件共同使结果成为可能”。二者不能 互相替代:相关事件排在前面,不代表它导致后果;一个关键条件没有出现在日志里,也 不代表它不存在。
36.2.1 触发条件、放大机制与失效防线
先建立三种时间
每条 timeline event 至少区分:
再加:
跨 PostgreSQL、Patroni、HAProxy、应用、主机和外部依赖时,wall clock 可能偏移;事务 XID、LSN、timeline、request token、日志 sequence 和 trace span 能建立局部 happens- XID、LSN、timeline、request token、日志 sequence 和 trace span 能建立局部的先于 关系(happens-before),但它们也不是一个全局时钟。不要为了画出整齐图表而把不确定 的秒级顺序伪造成毫秒精度。
因果链的五个位置
以一个假设性 PostgreSQL 连接事故为例:
“连接数过多”只是中间状态;“调大 max_connections”可能增强放大器。好的分析会继续
问工作为何被允许无界进入、为何重试不知 commit outcome、为何隔离和降级没有生效。
用反事实检验边
对每条 A -> B 写出可反驳命题:
反事实不是要求在线复现生产事故。可以用 trace、query plan、WAL/lock graph、隔离 fixture、历史对照或模型验证。若证据只支持相关性,就写“contributing hypothesis”, 不要升级成 root cause。
防线为什么失效
逐层检查:
| 防线 | 应回答 |
|---|---|
| prevent | 为什么错误配置、无界请求或危险变更能进入系统 |
| detect | 为什么没有在用户影响前/同时发现 |
| mitigate | 为什么隔离、限流、降级或围栏没缩小影响 |
| recover | 为什么 restore、failover、rebuild 或对账不够快/不够可信 |
“告警触发了”不等于 detect control 有效。若它晚于客户投诉、没有 route、缺少 owner 或每次都误报,它只生成噪声。
36.2.2 技术、流程、组织与认知因素
把 contributing factors 只写成技术缺陷,常常会在另一条路径重演同类事故。四个视角 互相约束:
技术
例如 Patroni 正确 promotion 仍可能遇到应用没有幂等 token;backup 完整仍可能因目标 选择或业务 delta 缺失而恢复错误 history。
流程
不要把“runbook 没写”当终点。继续问:这个判断是否适合 runbook?信息能否自动采集? 当证据冲突时是否有 stop line?runbook 是否随当前版本演练过?
组织
如果 database team 能看到 replication lag,却不知道哪个 slot 属于谁,问题不是
pg_replication_slots 文档不足,而是 retention owner 没有进入服务目录与升级路径。
认知
认知因素不是把责任还给个人。平台要让正确 mental model 更容易形成:明确 endpoint
语义、显示 target identity、把 evidence 与 inference 分栏、对危险动作展示前置谓词,
并让未知状态进入 STOP_AND_ESCALATE。
建一张因素矩阵
| 失效环节 | 技术 | 流程 | 组织 | 认知 |
|---|---|---|---|---|
| 进入 | 无 admission limit | 发布门未测压力 | owner 不明 | 把 timeout 当失败 |
| 扩大 | 即时重试 | 无降级触发线 | app/DB 各自优化 | 把 session 当容量 |
| 检测 | 缺 user SLI | 告警未演练 | 告警 owner 空缺 | dashboard 名称误导 |
| 恢复 | 无 token 对账 | runbook 缺 stop | 权威不明确 | 先重启再取证 |
矩阵不要求每格都填内容;它防止团队只在自己熟悉的层面找答案。
36.2.3 避免单一根因和个人归罪
“谁执行”仍是事实,“谁粗心”不是机制
可审计表述:
归罪表述:
前者保留动作、上下文和控制缺口,后者用人格标签替代可改变的系统条件。真正无责的分析 假设参与者在当时信息、目标、工具和压力下有局部合理性,然后追问系统怎样让危险动作 显得合理。
accountability 与 blame
无责不取消 accountability:
- incident commander 对响应目标与决策节奏负责;
- service owner 接受用户影响和 residual risk;
- action owner role 按期交付验证证据;
- reviewer 对结论的证据强度提出异议;
- management 为优先级、资源和到期 exception 作决定。
故意违规、欺诈、骚扰或安全事件可以进入独立的人事、法律或合规程序;不要把该程序 塞进技术复盘,也不要用“blameless”掩盖它。技术复盘仍分析系统如何预防、检测和限制 后果。
不要寻找一个可删除的“根”
复杂系统通常有多条必要/充分关系:
“五个为什么”可帮助继续追问,但线性链容易忽略并发分支。用 causal graph 表示:
flowchart LR
A["配置变更"] --> C["查询成本上升"]
B["统计信息过期"] --> C
C --> D["请求超时"]
E["立即重试"] --> F["队列放大"]
D --> F
G["无 admission gate"] --> F
F --> H["用户错误率上升"]
I["缺少 user-SLI page"] --> J["检测延迟"]
J --> H行动优先选能切断多条边、覆盖多类事故且可验证的控制,而不是只修最后一次 trigger。 例如目标身份 + exact scope 的发布门,可能同时降低误恢复、误切换、误删 slot 和误改 PGDATA 的风险。
复盘结论的证据等级
写作时保留等级。评审者要能指出哪条新证据会推翻结论;无法被反驳的“根因”通常也无法 指导一个可验证控制。
上一节:服务恢复不等于事件结束 · 返回本章目录 · 下一节:证据质量与决策复盘 · 查看全书目录 · 查看索引中心
36.3 证据质量与决策复盘
复盘拥有响应时没有的时间、权限和上下文,因此最容易犯 hindsight bias:把后来才知道 的答案投射给当时的人。决策质量必须按当时可用信息评估,结果质量则按后来完整 证据评估。
36.3.1 哪些事实当时可见,哪些后来才知道
建 knowledge timeline
普通 timeline 记录系统事件;knowledge timeline 记录响应者何时获得什么信息:
后来发现原告警是 replica、不是 primary,不要覆盖旧记录。追加:
这样才能问:“在 T1,接受写流量是否合理?”而不是用 T2 的答案责怪 T1。
四栏复盘表
| 当时可见事实 | 当时假设 | 后来证据 | 当前结论 |
|---|---|---|---|
| client timeout 上升 | primary 过载 | proxy backend errors + DB 正常 | 故障在 route |
| WAL 目录增长 | WAL 生成太快 | slot restart LSN 不动 | retention owner 阻塞 |
| 新节点可写 | failover 成功 | 旧主仍可接受直连 | authority 尚未安全 |
| checksum clean | 数据无损坏 | 业务 digest 漂移 | page 完整性与语义不同 |
要求每个结论能回指源证据,并明确 source identity。截图可帮助人理解,但通常缺查询、 时间窗、变量、完整返回和 hash;关键结论保留机器可读原始投影。
决策日志与复盘文档分离
响应期间的 decision record 应 append-only:
复盘可以评价该决定,却不能重写当时输入。若事故中没有决策日志,这本身就是一个证据 缺口;不要靠会后记忆补成精确逐分钟事实。访谈内容标记为 recollection,并与日志、 审计、metric 和 trace 交叉验证。
证据保真与最小披露
raw evidence 可能包含 query text、角色、IP、token、客户标识或 payload。采用两层:
去敏不应破坏关联键;可用 stable pseudonymous token、区间、计数与 hash。复盘仓库只放 projection 和原件位置/权限,不复制 secret 或个人数据。
36.3.2 哪些假设被验证,哪些动作靠运气
好结果不能证明好决策
四种组合都值得复盘:
| 决策过程 | 结果 | 判断 |
|---|---|---|
| 证据充分、边界清楚 | 成功 | 机制候选,仍需复验 |
| 证据充分、边界清楚 | 失败 | 模型或实现有缺口 |
| 猜测、无 stop/rollback | 成功 | near miss / luck |
| 猜测、无 stop/rollback | 失败 | 显性事故 |
“重启后好了”只证明重启与恢复同时发生。它可能清掉等待队列、终止事务、触发 failover、 刷新 cache 或碰巧等到下游恢复;没有前后证据就无法选出机制,也无法知道丢了什么。
为每个关键动作做机制审计
例如取消 exact application_name 会话后 lock waiters 清零,可以支持“这些 fixture
session 构成 flow pressure”;它不能证明任意高连接事故都应取消会话。又如从
known-good snapshot 恢复后业务 digest 匹配,支持该 fixture 恢复路线;它不能证明
生产 backup 覆盖同一范围。
验证假设,而不是验证故事
每个 hypothesis 写:
如果测试同时改变配置、版本、流量和拓扑,即使问题消失也无法归因。生产不能安全复现 时,在 clone、replay、模型或历史数据上验证,并把外推边界写清。
near miss 也进入控制系统
这些情况值得和事故一样记录:
- 错命令被 safeguard 阻止;
- 误切换前发现 system identifier 不符;
- dangerous parameter 在唯一副本执行前被 review 拒绝;
- restore candidate 偶然正确,但 target 没有审计来源;
- unknown request outcome 恰好没有重复副作用。
near miss 提供了低损失的失效路径证据。若只统计造成用户影响的事件,平台会忽略已经 穿透多层防线、仅靠最后运气没有出事的路径。
36.3.3 告警、日志和时间同步缺口
从问题反推 observation contract
不要以“多收日志”为默认行动。先列事故中无法及时回答的问题:
| 问题 | 所需信号 | identity/维度 | retention |
|---|---|---|---|
| 谁受影响 | user SLI / request outcome | service、operation、segment | 至少覆盖 SLO 窗口 |
| 查询为何慢 | wait、plan、query ID、I/O | cluster、db、role、query | 覆盖发布与周期负载 |
| 谁保留 WAL | slot/subscriber/archive | system id、timeline、slot owner | 覆盖恢复窗口 |
| 谁拥有写权威 | DCS、Patroni、timeline、route | cluster/member/endpoint | 覆盖 failover 前后 |
| 数据何时变化 | audit/WAL/business event | transaction/token/object | 由 RPO、合规决定 |
| 恢复是否可信 | backup/restore/business manifest | source/cutoff/candidate | 覆盖证据保留期 |
每个信号写 producer、collector、query、labels、刷新周期、缺失语义、owner、retention、 权限与成本。missing value 不能默认解释成 zero/healthy。
PostgreSQL 证据的时效与局限
PostgreSQL cumulative statistics、pg_stat_activity、pg_stat_replication、
pg_stat_replication_slots、pg_stat_wal、pg_stat_io 等提供不同观察面,但要记录:
- counter 是累计值还是当前 gauge;
- stats reset、server restart 和 failover 是否改变基线;
- 读取 snapshot、事务和刷新延迟;
- query text 是否截断或因权限不可见;
- standby 与 primary 的语义差异;
- extension/版本是否改变列和统计;
NULL、空行与零值分别意味着什么。
日志应使用可解析格式(如 csvlog/jsonlog)和稳定关联字段,但 log_statement=all
可能暴露敏感数据并产生高开销。优先记录必要 identity、duration、SQLSTATE、query ID、
application/client context;query 参数和 payload 按数据分类处理。
指标、日志与告警要能互相落点
一条值班告警(page)应先表达 user impact 或 error-budget threat,再链接诊断上下文:
按每个 instance 发 30 条 alert 通常不如按 service impact 聚合一次,再保留 instance 分解。告警规则也需要单元/合成 time series 测试:正常、阈值边界、缺失数据、抖动和 长期低速 burn 都要覆盖。
时间同步是证据基础设施
至少监控:
数据库 now() 是事务开始时间;statement_timestamp() 与
clock_timestamp() 语义不同。应用、PostgreSQL log、systemd journal、proxy 和
monitoring timestamp 还可能分别来自 event time 与 ingest time。复盘合并前先统一
UTC 展示、保留原时区,并标注误差;不能靠肉眼把相近 timestamp 当因果顺序。
缺口行动要可验收
不要写:
写成:
观察能力只有在问题发生前存在、事件中可访问、事件后可重放时,才是一项控制。
上一节:从时间线建立因果链 · 返回本章目录 · 下一节:把行动项变成控制 · 查看全书目录 · 查看索引中心
36.4 把行动项变成控制
复盘行动项的目标不是让团队“做过一些事”,而是改变下一次失效路径的概率、可见性、 影响或恢复质量。能否关闭一项 action,取决于控制效果证据,而不取决于 ticket 状态。
36.4.1 所有者、截止时间、验证方法与失效条件
合格 action contract
owner_role 保证组织结构变化后仍能路由;具体 assignee 可在工单中绑定。decision_owner
对资源、延期和 residual risk 作决定,不能把所有压力留给实现者。
关闭有四个阶段
例如新增一个 replication lag alert:
- rule 合并:implemented;
- VMAlert 已加载:deployed;
- evaluation 和 notification 正常:operating;
- 注入受控 lag 后按 SLI/route 触发且未误触其他场景:effective。
只有最后一步及其证据满足 closure contract,才标 effectiveness-verified。若控制只在
部分 service/version 上部署,状态也只能按该 scope 关闭。
写失效条件
没有 failure condition 的控制无法监控自身:
| 控制 | 失效条件示例 |
|---|---|
| backup | 最近可恢复点超 RPO,或隔离 restore 失败 |
| failover | 旧 writer 未围栏,unknown outcome 无法对账 |
| capacity gate | 未知 workload 绕过 budget,queue 无上限 |
| release gate | exact target/system identifier 缺失仍可执行 |
| checksum review | 扫描未覆盖全部声明对象或结果不可追溯 |
| runbook | 当前版本/拓扑不适用,参与者只能靠 hidden answer |
同时规定 control telemetry 的 owner 和 retention。否则控制悄悄失效,直到下一次事故 才被发现。
到期、例外和重验
配置、版本、工作负载和依赖持续变化。每项控制应有:
升级 PostgreSQL/Pigsty、改变 DCS/backup repository、迁移 region、重写事务边界、 修改 pool 或流量翻倍,都可能使旧演练证据失效。exception 不是永久豁免;到期时必须 重新接受风险、补充控制或完成修复。
36.4.2 自动检查、发布门、容量线与恢复演练
先选控制位置
越靠近错误进入点,通常越便宜:
不能自动 prevent 的风险,用 detect + mitigate;无法可靠恢复的数据,必须更早 prevent。 不要为追求“全自动”让一个弱分类器直接执行不可逆动作。
自动检查同时测试反例
正向测试只证明一个正确样本通过。控制至少覆盖:
对 migration,不只验证 SQL syntax;还验证 lock path、rewrite、replica lag、old/new application compatibility 和 rollback。对 restore,不只验证 PostgreSQL 启动;还验证 source lineage、target cutoff、business manifest、archive/backup 恢复和 route 未误切。
发布门要有明确 deny
未知状态默认 allow,会把 collector 故障变成生产变更。默认 deny 也不是全部答案: 紧急 break-glass 需要独立身份、范围、期限、记录和事后 review。
容量线是多资源 envelope
不要把压测 TPS 单值写进 gate。容量合同至少包含:
流量、数据倾斜、query mix、checkpoint、vacuum 和 backup 会改变 envelope。容量 gate 既可阻止超预算发布,也要在运行中检测 headroom 消耗;指标缺失时不能宣称有余量。
恢复演练验证整条链
周期演练不是每季度运行同一 happy-path 命令:
| 能力 | 至少验证 |
|---|---|
| backup/PITR | source、target、candidate、业务 delta、archive continuity |
| failover | authority、fence、client unknown、timeline、rejoin |
| overload | blind classification、scope、stop route、post-cleanup |
| integrity | preserve、checksum/amcheck、source selection、business invariant |
| secrets/access | break-glass、审计、到期回收 |
轮换 seed、故障点、参与者和 hidden truth;保留可比较指标,但不把单次练习排名成个人 绩效,否则参与者会优化剧本而不是暴露控制缺口。
36.4.3 不能验证的“加强意识”不是合格行动项
把愿望改写成系统行为
| 不合格 | 可验证改写 |
|---|---|
| 加强备份意识 | 每 90 天从随机 retained backup 隔离恢复;业务 manifest 全过 |
| 以后谨慎执行 | target 缺 system identifier、scope 或 rollback 时 gate 必须拒绝 |
| 完善监控 | synthetic user failure 在规定窗口触发 SLI 值班告警并附诊断链接 |
| 培训故障切换 | blind scenario 中先证明 fence/authority,再 reconcile unknown |
| 优化性能 | 固定 workload 下达到声明 SLI 且所有资源保留安全余量 |
| 更新文档 | 当前版本新值班者仅凭 runbook 完成演练,错误分支被 stop line 阻止 |
培训和文档可以是控制组件,但不能单独证明系统更安全。人会遗忘、轮岗并在压力下使用 默认路径;应同时改进工具、权限、界面、自动采集、guard 与平台默认值。
拒绝 solution-first action
从“升级版本”“增加节点”“换存储”“重写服务”开始,容易跳过控制目标。先写:
升级 PostgreSQL 或 Pigsty 可能修复已知 bug,也会改变扩展、配置、监控、backup 和 playbook 语义。它需要 ADR 与验证矩阵,不能作为通用复盘结论。
排优先级看风险,不看措辞力度
一种简单排序:
数字不是客观真理,而是迫使团队公开假设。优先:
- 能切断多条 causal edge;
- 覆盖多个 service/incident theme;
- 在影响前 prevent/detect;
- 具备明确、廉价的 effectiveness test;
- 降低 on-call 认知负担;
- 不制造更大单点或不可逆自动化。
低成本并不自动优先。“再加一条 alert”容易交付,却可能增加 noise;一次 target- identity gate 可能需要更多工程投入,但能同时阻断多类破坏性误操作。
action review 的停止线
以下任一成立,不应进入“完成”:
复盘质量最终体现在控制 registry 里有多少 action 被有效验证,而不是文档里列了 多少 bullet。
上一节:证据质量与决策复盘 · 返回本章目录 · 下一节:回写 SLO、SOP 与架构 ADR · 查看全书目录 · 查看索引中心
36.5 回写 SLO、SOP 与架构 ADR
事故揭示的新事实如果只留在 postmortem,日常开发、发布和值班仍会按旧假设运行。 复盘的下游消费者是 SLO、runbook、service catalog、inventory、ADR、测试与版本路线; 每个消费者都需要明确 revision 和 owner。
36.5.1 更新观察契约、告警规则与 runbook
observation contract 是接口
应用、PostgreSQL、Pigsty 组件和 incident process 对同一 identity 达成约定:
新增 label 不是免费:高基数会增加监控成本,敏感 identity 会扩大数据暴露。每个维度 回答“哪项决策需要它”,没有消费者的 telemetry 不应无限保留。
从 SLI 到诊断,不从组件告警猜影响
推荐两层告警:
例如 replica lag 可能威胁 RPO 或 read-only 用户路径,也可能只是一个无业务 route 的 重建节点。告警需要 topology、route 和 objective 才能分级。Pigsty 的 PostgreSQL、 Patroni、PgBouncer、HAProxy、host、backup 指标可作为诊断层,业务 good-event 仍要由 应用定义。
规则发布前测试:
每条值班告警链接一个能在当前版本执行的 runbook,而不是 dashboard 首页。
runbook 写判断,不堆命令
命令输出随 PostgreSQL/Pigsty 版本漂移;runbook 应说明指标和 SQL 的语义,并记录版本 适用范围。危险操作不要留一个通用变量空槽让值班者临时填目标,应从已验证 identity 生成 exact plan 并再次确认。
验证回写完成
“文档更新”需要:
- alert fixture 能进入对应 runbook;
- 新参与者在 blind tabletop 中请求到正确证据;
- 错误/缺失 evidence 进入 stop line;
- 文档链接、query 和权限在当前环境有效;
- postmortem action 反向链接 observation/runbook revision。
文档过期检测也可自动化:版本、owner、链接、最近演练时间和依赖对象进入 lint。
36.5.2 修正 RPO/RTO、容量和安全假设
objective、capability 与 observation 分栏
一次 sandbox failover 的 6,211.692334 ms acknowledgement gap 是 observation,不是
生产 RTO;一次 fixture PITR 的恢复时间也不包含审批、下载、容量申请、DNS、外部对账
和用户切换。反过来,一个写在文档里的 15 分钟 RTO 若从未演练,也不是 capability。
RPO 不是一个数据库数字
按结果类型拆分:
异步复制、archive 与 backup 各有不同 loss window。PITR 到正确 target 仍可能丢弃 target 后的合法写;数据库恢复也不会自动撤销已发出的支付、邮件或消息。因此 RPO 合同写数据类别、cutoff、source、对账方法和 exception。
RTO 分解而不是报一个 stopwatch
不同路线各自分布:
- 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 中的隐含假设:
每项写 evidence、margin、owner、invalidation event。将“单节点也够用”“replica 一定 最新”“内网可信”“备份每天成功”这种自然语言替换为可测谓词。
不因事故随意降低目标
若观测证明 objective 不可实现,有三个诚实选择:
- 投资能力达到业务目标;
- 调整产品/降级设计,缩小承诺范围;
- 与业务共同接受并批准新目标和 residual risk。
不能为了让报表变绿而单方面降低 SLO/RPO/RTO,也不能保留不可能实现的目标让值班者 承担结构性失败。
36.5.3 将必要变更纳入服务目录与版本路线
service catalog 是事故路由表
数据库服务条目至少包含:
这不是手工 CMDB 展示页。inventory 和 runtime 能自动投影的字段不重复录入;业务 owner、data class、objective、外部 dependency 与例外仍需显式治理。
用 ADR 记录为什么
配置告诉系统“是什么”,ADR 解释“为什么这样、在什么条件下仍正确”:
例如把 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:
不要把多个必要升级捆成一次无法归因的大爆炸。先解决阻塞链和可观测性,再 canary/ batch;每阶段都有 before/after、stop 和 rollback。
Pigsty 映射
Pigsty 的声明式 inventory 与幂等 playbook 适合承载 desired state;监控栈适合承载 control telemetry;pgBackRest、Patroni、PgBouncer 和 HAProxy 分别承载恢复、权威、 连接与路由机制。但平台不会替业务定义:
这些应用合同必须回写 service catalog,并与 Pigsty/PostgreSQL 证据在同一次演练中 共同验收。
路线变更也需要退出条件
每个 roadmap item 记录:
只有当旧例外、旧 runbook、旧 dashboard 和旧配置都被清点,版本演进才真正关闭; 否则值班时仍可能按过时入口执行。
上一节:把行动项变成控制 · 返回本章目录 · 下一节:将控制固化到平台 · 查看全书目录 · 查看索引中心
36.6 将控制固化到平台
平台化不是把所有决定自动化,而是让安全默认、身份、证据、审批和复位在每次操作中 一致出现。自动化适合执行已解析的意图;当 target、authority 或 evidence 仍有歧义时, 平台应停下来,而不是更快执行。
36.6.1 配置模板、验证脚本与策略即代码
控制从机器可读合同开始
模板只消除重复,不应隐藏高风险选择。默认填入:
- stable service/cluster naming 与 environment/data class;
- least-privilege role 与明确 HBA 来源;
- timeout、pool、backup、monitoring、安全和容量基线;
- version pin 与 extension compatibility;
- safeguard、exact target 和 destructive approval;
- owner、SLO/RPO/RTO 与验证 revision。
把业务密码、private key 或 raw token 从 inventory Git 中分离;模板引用受控 secret source,并验证存在性/权限,不输出值。
Pigsty inventory 是 desired state,不是全部事实
Pigsty 以声明式配置表达 node、cluster、instance、service、database、user 与参数, playbook 将其物化。推荐流程:
--check --diff 可帮助预览部分 Ansible 变化,但不能模拟所有 handler、运行时决策、
数据库锁、外部 repository 或 failover。preview 是证据之一,不是执行结果。
删除、重建和 PITR 等流程必须额外读取当前 identity 与 authority。Pigsty 的
pg_safeguard 可阻止危险 PGSQL 删除路径,但不能替代 exact inventory、备份验证、
流量排空和审批。安全控制应多层、互相独立。
原生证据复核平台结论
| 平台声称 | 回到原生/组件证据 |
|---|---|
| primary/replica 正常 | Patroni/DCS role、PostgreSQL recovery/timeline/replication |
| service route 正确 | HAProxy backend + endpoint 实际连接 identity |
| pool 正常 | PgBouncer pool/client/server state + PostgreSQL sessions |
| backup 正常 | pgBackRest info/check + 隔离 restore/business manifest |
| 参数生效 | pg_settings source/pending_restart + process/runtime |
| 监控覆盖 | collector target、query result、rule test、notification |
平台 UI 的绿色状态不能成为唯一证据;否则平台控制面故障时,团队失去验证路径。
策略即代码也要可解释
规则输出:
不可解释的 deny 会诱使人绕过控制;不可审计的 allow 会隐藏风险。policy 变更本身需要 review、测试、版本和回退,并覆盖 allow/deny/unknown 三类 fixture。
36.6.2 备份、切换、容量和维护的周期演练
建 capability calendar
按风险与变更频率决定周期,而不是所有项目“一年一次”:
| 能力 | 建议触发 |
|---|---|
| backup check | 连续运行;失败立即路由 |
| isolated restore | 固定周期 + backup/repository/version 大变更 |
| planned switchover | 维护周期 + topology/Patroni 变更 |
| unplanned failover tabletop/drill | 固定周期 + DCS/fencing 变更 |
| capacity benchmark | workload/hardware/major config 变化 |
| vacuum/freeze review | 持续趋势 + 数据增长/事务模式变化 |
| integrity check | 风险分层周期 + storage/ICU/major version 变化 |
| security access review | 固定周期 + owner/role/network 变化 |
| migration/upgrade rehearsal | 每次 candidate revision |
周期只是上限;invalidation event 应提前触发。
调度演练而不调度事故
故障注入限定 disposable clone 或明确无数据、无流量 sandbox。production chaos 需要 另一套组织授权,不能由“周期演练”四个字自动许可。
Pigsty 能承载的周期任务
- 通过监控栈持续观察 PostgreSQL、host、Patroni、PgBouncer、HAProxy、backup;
- 用 pgBackRest policy 与 exporter 观察 backup/archive,再在隔离目标实际 restore;
- 用 Patroni/Pigsty 服务模型演练计划切换和受控故障切换;
- 从 version-controlled inventory 重建 node/cluster,并验证 drift;
- 用 playbook tag/limit 管理作用域;
- 把 exporter query、alert rule、dashboard 与 runbook revision 共同发布。
具体 playbook、参数和输出会随 Pigsty 版本变化。运行前以已固定 release 的官方文档和 本地 source 为准;破坏性 playbook 不从书中复制到生产。
统一 evidence envelope
不同演练使用同一外壳:
统一 envelope 让平台能跨演练统计:哪些 control 过期、哪些 action 没有 evidence、 哪些版本从未恢复、哪些团队只跑 happy path。
演练失败不是坏成绩
演练在不伤害生产的前提下暴露:
这正是它的产出。禁止为了完成率修改 pass condition 或隐藏失败;修复后从同一合同 重新验证,并保留前次失败证据。
36.6.3 从单个补丁升级为默认护栏
从 incident-specific 修复抽象不变量
单点补丁:
默认护栏:
抽象层次以共同机制为准,不是越通用越好。一个巨大“万能安全框架”若无法描述 PostgreSQL timeline、replication slot、PITR target 或 collation dependency,反而 会隐藏领域事实。
safer default 的五个性质
- 自动采用:新 service 默认获得,不靠记忆 opt-in;
- 显式例外:绕过需要 owner、理由、补偿控制和到期;
- 可观察:知道 guard 是否执行、何时失效;
- 可版本化:配置、policy、runbook、dashboard 共同 revision;
- 可验证/可退出:有反例、回退和 retirement path。
例如:
业务仍要填 owner、data class、RPO/RTO、good event 与不变量;模板不能替它猜。
推广前做 blast-radius 管理
平台默认变更影响面大,按:
每阶段比较 compatibility、false positive/negative、延迟与资源成本、operator burden 和 rollback。guard 误拒绝所有紧急恢复也会制造可用性风险;保留受控 break-glass,并 监控使用频率。
建 control registry
跨 postmortem 查询重复 theme,而不是逐篇人工回忆。平台 backlog 优先合并能覆盖多个 incident/service 的控制,仍保留每个 incident 的特有 action。
平台完成的定义
一个控制成为默认护栏后,仍要证明:
“已经写进 Pigsty 模板”只完成第一步。最终效果必须在 PostgreSQL、组件、用户路径和 业务不变量上共同可见。
上一节:回写 SLO、SOP 与架构 ADR · 返回本章目录 · 下一节:实战:复盘四类事故并完成全书结业 · 查看全书目录 · 查看索引中心
36.7 实战:复盘四类事故并完成全书结业
最后一次实验不再连接数据库。它把第 32~35 章公开证据作为不可改写的输入,验证我们 能否在不夸大结论的前提下形成跨事故控制路线,并把全书能力映射为可答辩的证据。
36.7.1 汇总 ch32–ch35 的证据、决策与用户影响
实验合同
先读:
requirements.json:输入、风险和验收;incident-catalog.json:source pointer、影响、时间线与判断;control-backlog.json:十二项控制合同;capability-map.json:ch01~ch36 结业证据;negative-cases.json:36 个必须拒绝的语义篡改;lab-contract.md:事实、行动与认证边界;topology.mmd:离线数据流。
静态检查会创建临时输出,编译、验证后删除;它没有网络/SSH/数据库入口:
创建一份自己的 closure bundle:
compile 拒绝覆盖非空目录。all 只消费已有 bundle,重新验证 source hash、JSON
Pointer、控制合同、路线和 36 个 mutant。它不会执行 backlog。
输出结构
四份输入分别绑定:
每条 fact 保存:
编译器重新从源文件解析 actual。修改报告里的数字、pointer、source schema 或 hash
都会失败;事后解释也不能改写 knowledge_stage。
四份事故记录
| 记录 | 影响证据 | 决策 | 验收/边界 |
|---|---|---|---|
| ch32 误写 | fixture 1,000 victims、1,000 wrong outbox、外发 0 | exclusive PITR + audited delta | 恢复 1,000,保留 100 条合法后写,fixture loss 0 |
| ch33 主库失效 | 160 attempts、130 ack、最大 ack gap 6,211.692334 ms | fence → promote → reconcile → rejoin | ack missing 0、unknown unresolved 0;不是生产 RTO |
| ch34 资源压力 | flow 30/21 admitted/9 rejected;retained WAL 42,611,296 B | flow 与 retention 分开 route | exact fixture 清理;managed mutations 0 |
| ch35 完整性 | 1 byte、1 bad checksum、XX001;另一 case checksum 0 + version mismatch |
trusted copy;REINDEX 后 REFRESH | checksum/amcheck/业务不变量通过,原件保留 |
impact.kind 只能是 simulated 或 observed-sandbox。报告中没有真实用户、生产数据或
生产影响。
事实与叙事分离
catalog 为每个 incident 保留:
这使读者可以质疑叙事而不改写证据。例如 ch33 的 observed gap 确实是
6,211.692334 ms,但 claims_not_made 明确拒绝“这就是生产 RTO”;ch35 确实翻转
一个 byte,但不声称模拟真实控制器或内存故障。
36.7.2 找出跨事故重复出现的控制缺口
先找共同问题,不先宣布生产有缺陷
四次实验可以支持:
不能直接支持:
所以七个结果都标为:
正式报告中 production_gaps_confirmed=0。真实采用时,要用本地 inventory、policy、
runtime、访谈和演练逐项把 status 更新为 present/effective、gap、exception
或 not-applicable。
七个共同主题
| 主题 | 出现章节 | 生产评估问题 |
|---|---|---|
| observation contract | 32/33/34/35 | user impact、identity、数据库与业务证据是否可关联 |
| production claim gate | 32/33/34/35 | sandbox timing/route 是否会被误当目标或批准 |
| business validation | 32/33/35 | 恢复是否超越 process/topology 到业务事实 |
| reversible exact scope | 32/33/34/35 | mutation/cleanup 是否有目标、guard、rollback |
| unknown outcome | 32/33 | timeout/ack/commit 是否能按稳定 token 对账 |
| classifier stop route | 34/35 | 缺失/冲突证据是否阻止错误动作 |
| lineage and authority | 32/33/35 | source、timeline、writer authority 是否可证明 |
出现次数不等于优先级。用 production exposure、impact、现有控制强度、验证成本和多事故 覆盖率排序。
主题必须双向一致
每个 incident 列出 theme IDs,每个 theme 又列 incident IDs。validator 检查双向 membership,并要求至少两个 incident 才能称 cross-incident。删除一个主题、把主题 缩成单事故或引用不存在的 incident 都会被拒绝。
控制不是事故类型的一一映射
同一个 target-identity gate 可以保护:
- PITR 不恢复错 cluster;
- failover 不接纳错 lineage;
- overload mitigation 不取消无关会话/slot;
- rescue 不改写 managed/unique PGDATA。
同一事故也需要多类控制:
平台 backlog 优先寻找这类多边覆盖,但仍保留专用控制,例如 collation dependency 重建或 outbox 对账。
识别“控制存在但无效”
生产评估不能只问“有没有”:
有 backup job 但从未 restore,不算已验证 recover control;有 runbook 但 current version 无法执行,也不算;有 safeguard 但 generic token 可绕过 target identity, 只能算弱控制。
36.7.3 输出 90 天改进路线、平台 backlog 与复验计划
路线是参考 proposal,不是自动变更
十二项 action 均为:
每项包含 stable owner role、P0/P1、due day、source themes、control type、artifact、 verification procedure、pass condition、evidence to close、failure condition 与 revalidation days。采用者要把 role、scope、date 和 approval 映射到自己的组织。
Day 0~30:先让风险可见、危险动作可停
| Action | 控制 |
|---|---|
| A36-01 | 版本化 incident observation/evidence schema,并让缺字段 packet 失败 |
| A36-02 | destructive workflow 强制 exact target、data/traffic/authority 与 approval |
| A36-03 | 定义 request idempotency token 与 unknown-outcome reconciliation |
| A36-04 | 分开 user-impact SLI 与 PostgreSQL/host 诊断 telemetry |
这一阶段不承诺完成所有架构改造,先建立 identity、证据和 stop line。没有这些基础, 后续演练可能只是在更好地记录错误动作。
Day 31~60:证明四条恢复能力
| Action | 控制 |
|---|---|
| A36-05 | 多 PITR candidate + legitimate delta + business manifest |
| A36-06 | fence/failover/client reconciliation/rejoin |
| A36-07 | flow/retention blind classifier + ambiguous stop |
| A36-08 | checksum/amcheck/collation review + clone-only rescue |
| A36-09 | Pigsty inventory、release、safeguard 与 dangerous playbook review |
演练用隔离环境,生产不被当作故障注入场。失败产物被保留并转 action;不能为了按期 完成把 pass condition 改成“脚本退出 0”。
Day 61~90:把局部改进变成持续系统
| Action | 控制 |
|---|---|
| A36-10 | 用生产测量/有边界演练修订 SLO、RPO、RTO、容量与安全 ADR |
| A36-11 | 每月聚合重复 theme、过期 evidence 与 exception |
| A36-12 | blind 90-day game day + 独立 effectiveness review |
第 90 天不是项目结束。control registry 根据 revalidation_days 继续检查 30/60/90/180
天周期;版本、拓扑、workload 或依赖变化会提前使证据失效。
validator 如何对抗“纸面完成”
36 个 live mutant 覆盖六组失败:
正式结果:
公开摘要 SHA-256:
摘要见 closure-run.json。raw formal bundle 不发布,
因为公开教材只需要去敏结论和可重跑 source。
36.7.4 回看从 SQL 到生产的能力地图
十二个可答辩能力域
capability-map.json 将 36 章恰好覆盖一次:
| 能力域 | 章节 | 读者应能交付 |
|---|---|---|
| context/workflow | 1–2 | 精确身份、对象地图和可重跑任务 |
| model/integrity | 3–4 | 用 schema/type/constraint 编码业务不变量 |
| transaction/programming | 5–6 | 解释 MVCC、事务与服务端副作用 |
| query engineering | 7–9 | 从 plan/stats/workload 证明优化 |
| concurrency/release | 10–12 | 兼容发布、锁边界、rollback 与 contract test |
| extension workloads | 13–18 | 按语义、生命周期、风险和退出选择扩展 |
| service baseline | 19–22 | 用 Pigsty 交付 route/HA/backup/recovery |
| security/governance | 23–25 | least privilege、SLO/SOP 与 observation contract |
| capacity/maintenance | 26–28 | 可复现 envelope、调优、vacuum/freeze/bloat |
| evolution | 29–30 | migration/upgrade candidate、cutover 与 rollback |
| incident/recovery | 31–35 | blind classify、保护权威与证据、正确恢复 |
| platform learning | 36 | 将证据转成控制并独立验证效果 |
地图完整只证明教材没有漏章,不证明具体读者掌握。因此正式结果必须保持:
结业不是记忆命令
对每个域,读者完成四层答辩:
只会复制 psql、playbook 或恢复命令,不构成专家能力;只会讲原理、不能从 runtime
证明状态,也不构成。PostgreSQL 原生证据、Pigsty 平台状态和业务事实要互相校验。
建个人结业 portfolio
每份 evidence 标注:
真正的结业由你所在环境的 owner/reviewer 根据证据决定,而不是本书脚本替组织签字。
从哪里继续
读完全书不是把 PostgreSQL 变成“学完的知识”,而是获得一套持续更新的方法:
下一步选择一个真实但低风险的 service,把本节 12 项参考 backlog 做本地
present/gap/not-applicable/exception 评估,只批准一项最小、可验证改进。完成它、
保存效果证据、安排重验,然后再进入下一项。这比一次性宣布“数据库平台建设完成”
更接近长期可靠性。
上一节:将控制固化到平台 · 返回本章目录 · 返回全书导读 · 查看全书目录 · 查看索引中心