Files
PolyGateway/research-wiki/findings/2026-07-20-m2-soak-workload.md
T

67 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M2 真实数据压测:场景矩阵与数据清单
> **定位**: M2 压测 harness 设计文档的直接输入(调研产物,非设计本身)。依据: 2026-07-20 三项目工作负载调研(subagent,证据为 reference/ 文件:行号)+ 远端数据勘察(iomgaa@10.77.0.40)+ 已拉取语料的实测统计。
## 0. 决策记录(2026-07-20 人类拍板)
**不自研独立 mock 网关,压测直接打真实网关 + 真实数据**。理由: 调研证实无现成开源方案覆盖关键需求(静默缺 [DONE]/usage 精确可控),自研则"为醋包饺子";协议级故障的确定性测试已由 M1 进程内 MockTransport 单测钉死且长期保留,独立 mock 的边际价值不足。真实环境下的故障不靠造,靠**故障源混编**(§3)。成本上贵一点接受(预算上限 M2 设计定稿,人类签字)。
## 1. 语料盘点
| 语料 | 状态 | 体量 | 用途 |
|---|---|---|---|
| VT `generate_questions_telemetry.db` | ✅ 已拉取 `data/soak/` | 189MB,**376 条真实调用,messages p50=313KB / p95=1.2MB / max=2.5MB**(内嵌帧的多模态重载) | 直接回放: 真实重载 payload 分布,不用编造 |
| VT `harness.db` | ✅ 已拉取 | 50MB,traces/predictions 表(agent 搜索完整轨迹) | 挖取 S1 形态: system+多轮累积的真实长上下文序列 |
| VT `store/videos/*/frames/` | ⏳ 按需拉 | 300 视频 × ~90 帧 × ~190KB(全量 3.4G) | 多模态请求组装(1-4 帧/call 与 5-6 帧/call 两档);**建议先拉 20 个视频 ≈ 350MB** |
| CHS `data/real_data/` 等 | ⏳ 按需拉 | 4298 张超声 jpg(~150-230KB);假名,无需脱敏,拉取时顺手按索引匿名重命名 | 单图+固定短指令的无状态负载;**建议先拉 500 张 ≈ 100MB** |
| CHS `app/providers/vascular_assets/` | 本地 reference/ 已有 | 13 张参考图 | 拼接图场景(若纳入) |
| GovDoc | 无数据(人类确认) | — | 纯文本场景用 VT harness traces 的文本部分替代 |
## 2. 压测场景矩阵(6 个执行场景,收敛自调研的 9 形态)
> 原则: 场景以"请求生成器形态 × 治理能力覆盖"划分,全部经 `GatewayClient.chat()` 走完整洋葱;业务编排(arq/phase/租户配额)不在库内,不复刻。
| # | 场景 | 请求形态(数据源) | 并发/节奏 | 覆盖的治理能力 |
|---|---|---|---|---|
| P1 文本长上下文回放 | harness.db traces 还原 system+多轮累积(2K→数万 token 渐增),session_id/parent_call_id 链路照原样 | 16-32 并发,链式(单链串行 ≤40 步 × 多链并行) | 多轮大 prompt 吞吐、遥测链路、SQLite 持续写 |
| P2 多模态重载回放 | telemetry.db 376 条原样回放 + frames 组装新请求(1-4 帧与 5-6 帧两档) | 16 并发批(VT `TREE_BUILD_API_CONCURRENCY` 同量级) | 大 payload(300KB-2.5MB)下 SSE 稳定性、多模态摘要(缓存 key/遥测)开销、TPM 预扣结算 |
| P3 单图短指令高频 | CHS 超声图 + 12 字段 EXTRACT/CLASSIFY 固定 instruction,structured=pydantic 真实 schema | 50-100 并发(用户指定的目标强度主场景) | 高并发限流六道闸、结构化阶梯真实成功率、无 session 确定性负载 |
| P4 缓存双向 | 同 messages 重复(CHS 固定指令天然重复形态)+ VT cache_salt 破缓存;per-call namespace 隔离 | 混入 P3 流量 20-30% | 命中率统计、salt 强制 miss、namespace 隔离、Redis 持续读写 |
| P5 故障源混编 | P3 流量打到多源池: 健康源 + §3 故障源 | 50 并发持续 | 换源/退避/熔断开路-半开-恢复/冷却备忘/per_source_reasons,全部真实触发 |
| P6 混合浸泡(终测) | P1-P5 按比例混合(比例 M2 设计定),上千次请求、50-100 并发、2-3 小时(人类指定强度) | 持续 2-3h | §4 全部不变量 + 成本/延迟基线产出 |
## 3. 故障源混编清单(真实故障,零 mock)
多源池中混入**故意配坏的源**,故障在真实协议下自然发生:
| 故障源 | 配法 | 触发的真实路径 |
|---|---|---|
| 坏凭据源 | 真实网关 + 错误 API_KEY | 401 → SourceDeadError → force_open → 立即换源 |
| 黑洞源 | base_url 指向不可达地址(如防火墙 DROP 的内网 IP) | 连接超时 → TransientError(timeout)→ 退避重试 |
| 慢源 | 真实源 + 极紧 ttft/inter_token(如 1s/0.5s) | 看门狗真实触发 → 流中断 → 重试换源 |
| 紧闸源 | 真实源 + rpm=5 / max_concurrency=1 | 限流闸真实排队/fail-fast;RPM 窗口行为 |
| 间歇故障 | 真实网关自身的 429/5xx/空补全(M1 验收已证明会自然出现) | 免费的真实混沌 |
## 4. 不变量与记分板
压测记分板 = **我们自己的遥测库**(llm_calls,吃自己的狗粮)。结束时断言的硬不变量:
1. 记账归零: 全部源 inflight == 0;无泄漏租约;探针不悬挂(gate 可再准入)。
2. 遥测完备: llm_calls 行数 == 请求数(±取消双记的已知语义);call_id 无重复;error 分布与注入比例吻合。
3. 限额从未击穿: 按遥测时间戳重算,任意 60s 窗口内单源请求数 ≤ RPM 配置(故障源的闸)。
4. 内存平稳: 进程 RSS 首末差 < 阈值(窗口计数器/租约表无无界增长)。
5. 结构化成功率: P3 的 structured 档最终成功率(含重问)≥ 基线(首跑建立)。
6. 产出基线: 成本(usage 汇总)、延迟分位(p50/p95 ttft 与总时长)入 `tests/outputs/soak/` 报告。
## 5. 留给 M2 设计文档定稿的项
预算上限与网关保护(挑时段/全局限速值,人类签字);P6 混合比例;harness 落点(`tools/` 脚本,不入 pytest 门);CHS 图像子集拉取数量与匿名重命名脚本;traces→messages 还原器的实现;报告模板。
## 6. 数据拉取(2026-07-20 全部完成)
- [x] VT 两个遥测库 → `data/soak/`(239MB)
- [x] VT frames 子集 → `data/soak/vt_frames/`(20 视频、2480 帧、234MB)
- [x] CHS 超声子集 → `data/soak/chs_images/`(全库 4226 张均匀采样 469 张、84MB;患者姓名路径已平铺为 `chs_NNNN.jpg` 匿名索引,不留映射)
**测试隔离约定(harness 必须遵守)**: Redis 固定用专用 db3,每轮开跑前 `FLUSHDB`(仅 db3,我们独占;严禁碰 db0 共享库)+ 每轮独立 `cache_namespace=run_id` 双层隔离;回放场景每请求掺 run 级 cache_salt 破缓存(缓存行为归 P4 单测)。