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

6.1 KiB
Raw Blame History

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 全部完成)

  • VT 两个遥测库 → data/soak/(239MB)
  • VT frames 子集 → data/soak/vt_frames/(20 视频、2480 帧、234MB)
  • 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 单测)。