跳转到主要内容

31.6 实战:盲抽症状的桌面演练

本节不对数据库制造故障。它先从 Pigsty FULL/L3 沙箱采集一份最小只读上下文,再从 八个场景中盲抽两个,把本章协议压缩进前十五分钟。这里有两个容易混淆的 “level”:

Pigsty FULL/L3   监控接入层级:PG + node + pool + HA + logs
experiment L0   风险层级:read-only,在线 mutation 为零

参考 run 的响应由程序生成,用来证明合同和 validator 自洽;真正的人员训练必须由主持人 只发盲包、按请求提供证据卡并独立评分。

31.6.1 随机症状、误导性首发告警与缺失信息

先读合同

完整边界见 lab-contract.md,环境与验收条件见 requirements.json,响应协议见 incident-contract.json,拓扑与路由见 topology.mmd,参与者填写 response-template.json

先做纯静态检查:

static/labs/ch31/task.sh lint

完整参考 run 需要连接已经确认的四节点开发沙箱,但在线阶段只有只读 SQL、Patroni REST 和 pgBackRest info

export PG36_EVIDENCE_DIR="$(
  mktemp -d "${TMPDIR:-/tmp}/pg36-ch31.XXXXXX"
)"
export PG36_CH31_SEED=pg36-ch31-reference-v1

static/labs/ch31/task.sh all

也可以分步执行:

static/labs/ch31/task.sh capture
static/labs/ch31/task.sh exercise
static/labs/ch31/task.sh verify
static/labs/ch31/task.sh review

capture 显式使用 BEGIN READ ONLY、短 statement/lock timeout,只保存聚合会话、复制、 slot、archive、control identity 和缩减后的 HA/backup 上下文。它不读取业务行、不保存 query text 或原始日志。exercise 完全离线,不 pause Patroni、不 failover、不重启、不 terminate connection、不改路由、不恢复 backup。

八个场景让首发症状“不够用”

场景 首发误导 正确主路线
订单数下降、复制延迟为零 把同步副本误当历史副本 PITR
数据库健康、退款突然增长 把技术健康误当语义正确 PITR
写端点 503、primary up 把接入故障误当 primary 故障 HA
DCS timeout、节点自称 primary 相信单节点自报角色 HA
connection timeout、CPU 43% 只看 CPU,忽略连接槽和 pool OVERLOAD
满盘且 replica lag 把 lag 当根因,想手删 WAL OVERLOAD
checksum mismatch、lag 为零 把同步状态当完整性证明 INTEGRITY
seq/index 结果不同 REFRESH VERSION 当重建 INTEGRITY

每个 blind packet 只包含:

  • initial signal 与已报告用户影响;
  • 可以请求的证据卡 ID、问题、层次和时间成本;
  • 十五分钟 deadline 与作答规则。

它不会包含 hidden truth、严重度答案、route、required card、safe/dangerous action 或 证据 observation。facilitator-pack.json 才保存这些内容。场景源文件本身是公开教材, 所以这种隔离是教学流程而非密码学保密;正式考核应由主持人控制文件访问或使用私有 派生场景。

“没有证据”也要进入记录

参与者请求一张暂时不可得的证据卡时,主持人应回答:

unavailable / permission denied / collector down / retention expired

而不是替换成“正常”。参与者要决定是换独立观察面、升级权限 owner、缩小动作,还是 因为关键事实缺失而保持 stop line。事故能力的一部分就是在证据不完整时拒绝不安全的 确定性。

31.6.2 分别按单人和团队模式完成前十五分钟

主持方式

  1. 主持人运行参考工具并单独保管 evidence directory;
  2. 只把一个 blind packet 与空白 response template 发给参与者;
  3. 参与者先声明五轴影响和当前 severity;
  4. 参与者按 ID 请求证据卡,主持人从 facilitator pack 逐张返回 observation;
  5. 每个有副作用的建议都要求 risk、owner、expected、stop、rollback;
  6. 第 15 分钟停止,参与者发布状态更新并完成 handoff;
  7. 最后才揭示 hidden truth、required cards、safe/dangerous actions。

参考 run 固定 seed 抽到:

solo  integrity-collation-index  -> INTEGRITY
team  data-accidental-delete     -> PITR

随机 seed 可改变题目,但 runner 会保证两题属于不同路线。不要重复抽到熟题就假装完成 盲测;应记录 seed、场景使用历史和参与者是否见过答案。

solo 与 team 使用同一张答卷

solo 模式四个 role 都由 solo-oncall 承担,但按时间串行切换;team 模式要求 IC、 operator、scribe、business liaison 是四个不同 actor。两者都必须做到:

required evidence complete minute < route decision minute <= 15
all actions belong to declared safe action set
dangerous_actions_executed = []
decision log starts at minute 0 and ends at minute 15
at least one stakeholder update before or at minute 15
production_authorized = false

团队可以让多个 R0 track 并行,但仍只有一个 operator token;单人不能用“我自己复核过” 冒充独立 R2/R3 review。

一份可复用评分表

项目 分值 失分例
五轴影响与 severity 15 把 unknown 写成无影响
现场和恢复能力保护 20 未围住 writer;建议删除 WAL
跨层证据选择 20 只看一张 dashboard
技术 route 与目标 15 severity 直接决定 failover
决策日志与 stop line 15 动作无预期、回退和结果
角色、升级与沟通 10 多人同时改;不报 unknown
机密与生产边界 5 粘贴凭据;宣称已获生产授权

发生以下任一项应直接判定需要重练,不用总分掩盖:

  • 在证明 writer 唯一前 promote;
  • 删除现役 pg_wal
  • 在原始证据上执行覆盖式修复;
  • 未经业务 owner 直接覆盖事后合法写入;
  • 把 facilitator 未提供的信息自行当成事实。

程序生成的 responses.json 只是一份 schema-complete reference,不是答题者成绩。真人 评分要保存自己的 response、主持人发卡时间和讨论录音/记录权限,并由未参与执行的人 复核。

31.6.3 在 Pigsty L3 输出时间线、决策日志、证据包与路由选择

正式参考现场

正式 run 在 pg-test 捕获:

PostgreSQL version              18.6
system identifier              bound to pgBackRest stanza identity
timeline                       11
Patroni                         1 running primary + 2 running replicas
physical replication streams   2, max sent/replay gap 0 bytes
pgBackRest status / backups     0 / 6
SQL transaction                 READ ONLY
raw query / raw log             absent / absent
online mutation                 none

现场的 pg_stat_archiver.failed_count 为 21,但 last failure 在 2026-07-29T18:57:58Z,last archived success 在 2026-07-30T01:36:16Z。这正说明累计失败数不能直接解释成“当前归档故障”。本章不因 看到 21 就 reset 统计或修改 archive;它保留 reset 与时间,交给真实趋势和 backup 证据解释。

“repo 中有 6 份 backup”也不等于恢复通过。本次没有执行 restore,公开结论只写 pgbackrest_status=0 和 backup count;第 21、32 章的恢复证据才回答可恢复性。

私有证据与公开摘要分层

证据目录包含:

preflight-evidence.json
blind-packets.json
facilitator-pack.json
responses.json
exercise-evidence.json
negative-report.json
validation-report.json
public-summary.json
review.txt

目录权限为 0700、文件为 0600。review 拒绝 credential URI、SCRAM verifier、 private key、clear password、raw SQL/log field,并检查 preflight、盲包、答案、 exercise 与 public summary 属于同一 run。

公开参考摘要见 incident-run.json。它只保留环境轮廓、路线、安全 边界与验收计数,不公开 facilitator 答案和 live 细节。

反例验证防止“格式漂亮的伪响应”

正式 validator 要求:

31 declared counterexamples rejected
18 live evidence mutants rejected
12 source files hash-bound

它会拒绝:

  • severity 被允许直接选择 route;
  • blind packet 泄露 hidden truth 或 expected route;
  • required evidence 未齐就决策;
  • solo/team role 语义不成立;
  • action 属于 dangerous set 或晚于 minute 15;
  • decision log 缺 expected/stop/rollback;
  • live capture 不是 READ ONLY、cluster/timeline/topology 不匹配;
  • backup system identifier 不同;
  • source/upstream/evidence hash 被替换;
  • 任何 production gate 被打开。

对同一份私有证据可以重复:

static/labs/ch31/task.sh verify
static/labs/ch31/task.sh review

但修改实验源文件、盲包或 response 后,不能继续复用旧 exercise hash;应开启新 run, 保留旧包作为历史。

本章交付物不是根因报告

合格的第 31 章 handoff 应包括:

severity and five-axis basis
current user/data/recovery impact
authoritative or still-unknown writer/timeline
active fences and automation state
evidence manifest and decision timeline
chosen route and alternatives rejected
first safe action / stop line / owner
next update and escalation requests

参考 run 最终结论是:

read-only-context-and-tabletop-protocol-demonstrated
human_competency_claimed = false
production_ch31_gate = pending

下一章从第一条路线开始:面对已经提交的误删误改,怎样选准恢复目标、在隔离实例完成 PITR,并把历史正确状态与事后合法写入重新合并。


上一节:单人值守与团队响应 · 返回本章目录 · 下一章:PITR 与误操作恢复——妙手回春 · 查看全书目录 · 查看索引中心