34.8 实战:同一症状、两种成因
本实验不给操作者“连接风暴实验”和“WAL 实验”两个有答案的按钮。runner 随机安排 两种根因、生成无语义 case ID,classifier 只能看证据:
common alert: postgresql-resource-headroom-at-risk
case opaque-A:
connection / retention / engine / filesystem observations
case opaque-B:
connection / retention / engine / filesystem observationshidden answer 在分类完成后才用于验收。这样练习的是判型,不是背剧本顺序。
34.8.1 随机注入连接风暴或 WAL 保留
先读实验合同
- 环境、阈值与风险:
requirements.json - blind classifier 路由:
classification-contract.json - 34 个反例:
negative-cases.json - 人类可读边界:
lab-contract.md - managed/disposable 拓扑:
topology.mmd
先做不连接远端的静态检查:
static/labs/ch34/task.sh lint只读现场采集:
export PG36_EVIDENCE_DIR="$(
mktemp -d "${TMPDIR:-/tmp}/pg36-ch34-capture.XXXXXX"
)"
static/labs/ch34/task.sh capture它读取 managed pg-test 的 Patroni 成员、primary system identifier/timeline、连接与
replication slot 投影,并确认 pg-test-3 没有残留实验 root。它不执行 SQL 写入、
cancel、slot、service、route 或 DCS 变更。
完整演练 guard
export PG36_EVIDENCE_DIR="$(
mktemp -d "${TMPDIR:-/tmp}/pg36-ch34.XXXXXX"
)"
export PG36_CH34_TARGET=pg36-l2-vagrant/pg-test
export PG36_CH34_NONPRODUCTION=true
export PG36_CH34_PRODUCTION_DATA=false
export PG36_CH34_PRODUCTION_TRAFFIC=false
export PG36_CH34_CONFIRM=BLIND_FLOW_VS_RETENTION_CH34
static/labs/ch34/task.sh drill:overload任一 guard 不符,runner 在创建远端目录前退出。evidence directory 已包含文件也会被 拒绝,避免混合两次 run。
隔离引擎
在线 fault 不发生在 managed PostgreSQL,而是在 pg-test-3 创建:
/tmp/pg36-ch34-overload-<uuid>/
.pg36-ch34-owned
data/
socket/
postgres.log关键限制:
PostgreSQL 18.4
listen_addresses=''
Unix socket mode 0700
port 55444 only names the private socket
max_connections=24
superuser_reserved_connections=3
max_replication_slots=4
checksums=on
not a Patroni/DCS/HAProxy/PgBouncer member实验不注入 OOM、不填满文件系统、不 drop cache,也不执行错误动作。无论正常或失败, 只在 marker 与 exact UUID root 匹配后停止临时 postmaster 并删除整个一次性目录。
两个真实 fault
FLOW:
30 non-superuser psql clients
same advisory lock
one holder sleeps for 20 seconds
other admitted clients wait on Lock
excess clients hit the connection boundaryRETENTION:
one exact inactive physical replication slot
immediately reserved restart_lsn
bounded WAL generation
stop after retained >= 32 MiB
hard cap 128 MiBmax_slot_wal_keep_size=-1 只在这个一次性实例中用于稳定展示保留机制,绝不是生产推荐
值。
34.8.2 在不知道答案时先判型,再选择动作
classifier 唯一允许读取的字段
{
"case_id": "opaque",
"observed_at": "UTC",
"connection": {
"observed_sessions": 0,
"connection_rejections": 0,
"lock_waiters": 0
},
"retention": {
"inactive_physical_slots": 0,
"retained_wal_bytes": 0
},
"engine": {},
"filesystem": {}
}判定合同:
FLOW =
observed_sessions >= 18
AND connection_rejections >= 1
AND lock_waiters >= 1
AND inactive_physical_slots = 0
RETENTION =
inactive_physical_slots = 1
AND retained_wal_bytes >= 33554432
AND connection_rejections = 0
both or neither =
STOP_AND_INVESTIGATEclassifier 不读取 hidden-answers.json。validator 会比较 case identity set、字段完整性、
classifier provenance 与 hidden answer;blind packet 若带 truth 或 expected_route
字段反而判失败。
正式 run
公开证据:
overload-run.json
run id 1ae188cd-e7f2-4724-98d8-fe166cf4e33f
random order RETENTION -> FLOWWAL case 先出现,但 classifier 没把“第一个”解释成 flow:
inactive physical slots 1
retained WAL 42,611,296 bytes
connection rejects 0
route PRESERVE_RETENTION_EVIDENCEconnection case:
attempted clients 30
observed sessions 21
connection rejects 9
lock waiters 20
inactive physical slots 0
route RELIEVE_FLOW_PRESSURE24 个 max_connections 减去 3 个 superuser reserved slots,正好留下 21 个普通 admission;
其余 9 个被拒绝。20 个 lock waiter 加 1 个持锁/睡眠 session 又构成 21 个已进入会话。
这是该临时配置下的可解释闭环,不应外推为任何生产集群连接预算。
34.8.3 对流量型恢复服务,对保留型完成安全路由
FLOW 动作
runner 用 run-specific application prefix:
pg36-ch34-flow-<run-prefix>-<client-number>只对匹配 prefix 的 backend 执行 pg_cancel_backend。正式结果:
cancel signals sent 21
broad cancel used false
max_connections changed false
fallback client terminate/kill 0/0
post fixture sessions 0
post SQL probe 1若 backend 没在 deadline 内退出,唯一 fallback 是 runner 直接持有的 exact child process;
不会扫描或终止主机上的其他 psql,更不会触碰 managed pg-test。
生产映射不是“按 prefix 杀 21 个会话”,而是:
identify admission class and owner
stop producer/retry
preserve admin headroom
cancel exact expired/low-value work
verify queue and useful completionRETENTION 动作
runner 先保存:
slot_name/type/active
restart_lsn
retained_wal_bytes
wal_status/safe_wal_size/invalidation_reason
filesystem projection然后只 drop 带本 run identity 的 disposable slot:
scope exact-owned-disposable-slot
evidence preserved before action
manual pg_wal deletion false
post physical slots 0
post SQL probe 1生产上的 inactive slot 没有这份授权。对应动作是联系 owner、确认 consumer/backup/RPO, 恢复消费或建立新的恢复起点,再由明确负责人批准 exact release。
managed 边界复核
before/after 都要求:
pg-test-1 primary running
pg-test-2/3 replica streaming
system identifier unchanged
timeline 19 unchanged
chapter fixture sessions 0
matching disposable roots []公开报告因此写的是 managed mutations=0,而不是声称在 Pigsty managed cluster 上
验证了饱和行为。
34.8.4 输出动作时间线、误判代价与容量改进项
evidence bundle
before.json
exercise/
run-manifest.json
source-manifest.json
exercise-evidence.json
blind-packets.json
hidden-answers.json
cleanup.json
classification.json
after.json
validation-report.json
negative-report.json
public-summary.json
review.txt已有完整证据包可重复做只读校验:
export PG36_EVIDENCE_DIR=/absolute/evidence/ch34/run
static/labs/ch34/task.sh allvalidator 将 12 个实验 source file 与 SHA-256 绑定,并实际构造 34 个 mutant。反例覆盖:
production/managed mutation guard opened
scenario or classifier contract weakened
blind packet leaks truth or misses fields
classification duplicated/unsupported/wrong
flow evidence below threshold or broad cancel
retention slot/bytes/active state falsified
manual WAL deletion or leftover slot claimed
cleanup root left behind
production gate falsely approved34 个都必须被拒绝;声明有 34 条 JSON 并不等于做了对抗验证。
误判代价
| 误判 | 结果 |
|---|---|
| flow 当 retention | 不限制 admission,连接失败与队列继续 |
| retention 当 flow | cancel session 不推进 restart_lsn,WAL 继续增长 |
| unknown 强判 flow | 可能 terminate 关键/大事务并制造回滚峰值 |
| unknown 强判 retention | 可能 drop 有效 slot、破坏 consumer/RPO |
手工删 pg_wal | 破坏 crash recovery、复制、备份与现场证据 |
因此 unknown route 不是实验的“第三种错误答案”,而是证据不足时唯一正确的动作类别。
从实验回写容量控制
这次结果至少导出四个可验证改进:
- 为普通连接显式保留 admin/reserved budget,并让 pool 上限小于硬边界;
- 对 application pool 总和、retry 与启动 prewarm 做全局预算;
- 对每个 slot 记录 owner、active、restart/catalog xmin、retained bytes 与推进率;
- 告警同时包含“当前余量”和“增长率/耗尽时间”,并带 FLOW/RETENTION 判型链接。
不能从这次实验导出:
production max_connections should be 24
every inactive slot may be dropped after 32 MiB
42 MB WAL implies a disk incident
exact cancel always has zero fallback
managed Pigsty can tolerate the same storm最终门禁保持:
production_ch34_gate=pending上一节:平台级流量控制与证据 · 返回本章目录 · 下一章:数据抢救与工程取证——起死回生 · 查看全书目录 · 查看索引中心