docs: record P6 soak baseline and scoreboard artifact fixes
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# P6 混合浸泡首跑基线与记分板三重伪击穿修复
|
||||
|
||||
- **日期**: 2026-07-21;**run_id**: `soak_20260721_050750`
|
||||
- **结论**: 8000 次调用全部完成,库自身零缺陷;记分板两项 FAIL 均为**测量口径缺陷**(三重伪击穿),修复后离线重裁全部 PASS。修复分支 `fix/soak-scoreboard-clock`。
|
||||
|
||||
## 1. 运行参数与规模
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| 场景 | P6 混合(P1 .10 / P2 .20 / P3 .35 / P4 .15 / P5 .20),SOAK 五源故障池 |
|
||||
| 预算/实际 | 8000 次(签字帽)/ 8000 次全部完成;token 1401 万(硬顶 2 亿) |
|
||||
| 拓扑 | 2 worker × 32 并发 = 64 在途;限流/熔断/缓存全 Redis(db3);Postgres 遥测 |
|
||||
| 用时 | 05:07–06:54,约 1h47m(3h 上限内) |
|
||||
| 成本 | **23.42 元**(价格表首次生效: 输入 2.1/输出 8.4 元/M tok;缓存命中 token=0 天然零成本) |
|
||||
|
||||
## 2. 结果基线(P6 首跑,后续回归对照)
|
||||
|
||||
| 指标 | 值 | 说明 |
|
||||
|---|---|---|
|
||||
| 总成功率 | 4648/8000 = **58.1%** | 五源池 3 坏 1 紧闸;窗口成功率从开局 40% 爬至尾段 73%(熔断学习 + 缓存变热) |
|
||||
| 缓存命中 | 2373 次 | P4 复读流量生效,命中秒回零成本 |
|
||||
| 延迟(成功行) | 总时长 p50/p95 = 6.8s/48.1s;TTFT p50/p95 = 22.0s/53.2s | p50 远低于 P3 纯健康池(16.9s)系缓存命中行拉低;非缓存行与 P3 同量级 |
|
||||
| P3 结构化成功率(P6 内嵌) | 0.218 | 故障池 + 网关 429 高压下的口径,**不可**与纯健康池基线 0.942 直接对比 |
|
||||
| RSS | 实时 ps 采样: 10min 119MB → 40min 起稳定 36MB 至结束 | 无泄漏;峰值系 harness 自身无界入队(见 §4) |
|
||||
|
||||
错误分布大头(共 20146 遥测行): 网关侧 429 限速 4845(minimax_5 3773 + minimax_1 996 + minimax_4 76)、紧看门狗掐流 3622(inter_token 3390 + ttft 232)、真实空补全 2211、retry_exhausted 终态 3318、黑洞超时 230、坏 key 31。
|
||||
|
||||
**治理行为实证**: 黑洞源走完 攒失败→开路→仅探针漏过 全周期(全程 230 次超时,开路后每 5 分钟仅 1 次探针);坏 key 源 force_open 后基本从遥测消失;跑后记账归零、探针不悬挂、call_id 唯一全 PASS。
|
||||
|
||||
## 3. 三重伪击穿: RPM "FAIL" 根因链
|
||||
|
||||
记分板判 `minimax_4`(RPM=5)单分钟 6-10 次。逐层排查(每层修完仍 FAIL 才发现下一层):
|
||||
|
||||
| # | 口径缺陷 | 证据 | 修复 |
|
||||
|---|---|---|---|
|
||||
| 1 | 用**完成时刻**(created_at=落库时刻)聚桶,调用延迟达分钟级,多个准入窗口的调用挤进同一完成分钟 | 准入时刻 = created_at − latency 重算后分布改变 | 按准入时刻聚桶 |
|
||||
| 2 | 用**本机钟**聚桶,而限流器窗口 id 来自 **Redis 服务器钟**(`limiter.py:_window_id`,CHS 移植的多进程口径统一设计) | 实测 Redis 钟偏移 **+30.98s**;密集分钟 10 次准入在第 ~29 秒恰可切 5+5 | 记分时实测偏移并校正;秒级截断噪声给 ±2s 贴边豁免(邻窗有余量才可豁免) |
|
||||
| 3 | **缓存命中行计入 RPM**——缓存在限流闸之前返回,未耗名额未打网关,但"遥测必录"使其带原源名落库 | minimax_4 共 579 行中 **347 行 cache_hit=1**;剔除后所有窗口 ≤5 | RPM 口径排除 cache_hit 行 |
|
||||
|
||||
修复后离线重裁(`--rescore`,不产流量): **RPM PASS**。
|
||||
|
||||
## 4. RSS "FAIL" 根因: 峰值口径 + 无界入队
|
||||
|
||||
- `_rss_mb` 用 `ru_maxrss`——**历史峰值只增不减**;判"增长 782MB"实为开局峰值。
|
||||
- 峰值来源是 harness 自身: 分发循环 15 秒内把 4000 任务/worker(含 P2 ~313KB 图负载)全量 `create_task`,信号量只限执行不限入队;顺带使 `--max-hours` 截止检查随分发结束而失效、执行期无进度打印。
|
||||
- 库无泄漏: 运行期实时 ps 采样 36MB 稳定 90 分钟(本 finding §2)。
|
||||
|
||||
**修复**: ① `_rss_mb` 改 `ps -o rss=` 当前值;② 分发改 `_paced_dispatch` 有界模式(先占并发名额再建任务),截止检查全程有效、内存峰值受限、进度行全程可见;③ 旧格式结果(仅峰值序列)重裁时判 SKIP 不判 FAIL。
|
||||
|
||||
## 5. 交付物
|
||||
|
||||
- `tools/soak/scoreboard.py`: `inv_rpm_never_exceeded` 新口径(准入时刻 + 服务器钟偏移 + 贴边豁免 + 排除缓存行)。
|
||||
- `tools/soak/run_soak.py`: `_rss_mb` 当前值、`_paced_dispatch` 有界分发、`_redis_clock_offset_s`、`--rescore RUN_ID` 离线重裁模式。
|
||||
- 测试: `tests/unit/test_soak_corpus.py` 新增 6 用例(先红后绿),全套 356 过 0 败覆盖 90%。
|
||||
- 重裁报告: `tests/outputs/soak/soak_20260721_050750.md`(全 PASS/SKIP)。
|
||||
|
||||
## 6. 经验沉淀
|
||||
|
||||
1. **不变量的口径必须与执法者同源**: 限流器用什么时钟、在哪个时刻、对哪些流量执法,记分板就必须用同样的三元组重算;任何一元错位都产生伪击穿。
|
||||
2. 分布式系统验收前先测**时钟偏移**(本实验室 Redis 快 ~31s)。
|
||||
3. `ru_maxrss` 不可用于"平稳性"断言;峰值与当前值是两个量。
|
||||
4. "遥测必录"(含缓存命中)与"限流口径"(仅真实过闸流量)是两个集合,消费遥测时必须显式选择。
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
type: finding
|
||||
node_id: finding:p6-soak-baseline
|
||||
title: "P6 混合浸泡首跑基线与记分板三重伪击穿修复"
|
||||
date: 2026-07-21
|
||||
---
|
||||
|
||||
# P6 混合浸泡首跑基线与记分板三重伪击穿修复
|
||||
|
||||
> 正文见 [2026-07-21-p6-soak-baseline.md](2026-07-21-p6-soak-baseline.md);结论: 8000 次全预算完成、库零缺陷,两项 FAIL 均为记分板口径伪击穿(完成时刻聚桶/本机钟 vs Redis 钟偏移 31s/缓存行计入 RPM + ru_maxrss 峰值),修复后重裁全 PASS。
|
||||
|
||||
Reference in New Issue
Block a user