已关闭
[Medium][optix/multihost_infer] health() 每次轮询发真实推理请求,压测运行期被 scheduler 每秒注入探针并可能误杀 trial #411
mjsz创建于 13 天前关闭于 5 天前
13 天前 添加了label:bug
kai1949
13 天前 评论:
13 天前 评论:
/label add triaged
👋 您好,欢迎向 MindStudio-Modeling 提交 Issue!
我们已收到您的反馈,感谢你对开源社区的支持。🎉
📅处理时效: 维护团队将在8小时内 查看并回复您的问题(工作日)。
🔍自助查询: 在等待期间,建议您先查阅以下资料,可能已有解决方案:
📖 MindStudio-Modeling官方文档
📝 贡献者指南
请确保 Issue 描述清晰,包含复现步骤和日志,这将帮助我们更快定位问题。谢谢!


13 天前 添加了label:triaged
8 天前 关联了里程碑:MindStudio 26.3.0
8 天前 关联了里程碑:MindStudio 26.2.0
6 天前 关联了pull request:【多机混布】health检查接口增强& 杀残留进程增强
5 天前 issue状态由 TODO 改变为 DONE
5 天前 添加了label:resolved
5 天前 关闭了 issue
5 天前 添加了label:resolved
Bug 验证报告:PR686 发现 3(health() 探针在压测运行期每秒注入真实推理请求)
bugverify-pr686-f3-20260903-01(v3:2026-09-04 用户路径实测回填完成)msmodeling optix -e multihost_infer -b evalscopeperf --backup,tcpdump 与 vLLM API 访问日志双通道证实:压测运行期间探针推理请求每秒 1 条持续注入,贯穿整个压测窗口。[Medium][optix/multihost_infer] health() 每次轮询发真实推理请求,压测运行期被 scheduler 每秒注入探针并可能误杀 trialProblem
MultiHostSimulator.health()在 master/health返回 200 时无条件调用test_cluster_simple()发一条真实 completion 请求(prompt="Hello"、max_tokens=10、timeout=30,simulator.py:78-95,123-129)。设计意图仅覆盖启动等待,但 optix scheduler 的monitoring_status()在 benchmark 压测运行期间对"实现了health()且不是内置Simulator类"的模拟器每秒调用一次health()(optix/optimizer/scheduler.py:520-528,536time.sleep(1))。MultiHostSimulator结构化满足SupportsHealth、不满足内置排除条件,落入该分支。后果:① 压测窗口每秒 1 条额外推理请求污染吞吐/延迟测量;② 高负载下探针瞬时失败 →health()非 running → scheduler 抛SubprocessError误杀当轮 trial(scheduler.py:522-528)。Reproduction(用户方式:命令 + 配置,与 README《使用》章节一致;已实测可跑通)
环境:任意可运行 vLLM 的 Linux(实测在 8×910B2 共享服务器的 vllm-ascend:v0.22.1rc1 容器内、单 NPU、Qwen3-0.6B 权重完成)。
Step 1: 写两个配置文件(内容整体内联,实测原样可用)
集群配置
<插件目录>/config.toml(单机:只写 node,不写 workers;CLUSTER_CONFIG_PATH指向它):docker_use_sudo = false [vllm_mix] chips_per_node = 8 [[vllm_mix.node]] host = "<本机IP>" nic_name = "<本机网卡名>" # 显式指定,跳过探测寻优配置(
optix/config.toml的[vllm]+[evalscopeperf]段):[vllm] [vllm.command] host = "0.0.0.0" port = "9975" model = "/data/models/Qwen3-0.6B" # 任意可加载的小模型 served_model_name = "qwen" others = "--max-model-len 4096 --gpu-memory-utilization 0.4" [[vllm.target_field]] name = "MAX_NUM_BATCHED_TOKENS" config_position = "env" min = 4096 max = 4096 dtype = "int" value = 4096 [[vllm.target_field]] name = "MAX_NUM_SEQS" config_position = "env" min = 32 max = 64 dtype = "int" value = 32 [[vllm.target_field]] name = "CONCURRENCY" config_position = "env" min = 16 max = 16 dtype = "int" value = 16 [[vllm.target_field]] name = "REQUESTRATE" config_position = "env" min = 16 max = 16 dtype = "float" value = 16 [evalscopeperf] output_path = "/tmp/evalscope_out" [evalscopeperf.command] url = "http://127.0.0.1:9975/v1/completions" model = "qwen" tokenizer_path = "/data/models/Qwen3-0.6B" dataset = "openqa" # evalscope 内置数据集(本地 jsonl 路径不被识别为数据集插件) outputs_dir = "/tmp/evalscope_out" others = "--parallel 16 --number 400"Step 2: 另开终端挂抓包(探针观测点)
tcpdump -i lo -A -s0 'tcp port 9975' > probe_capture.txt 2>&1Step 3: 启动寻优(README 同款命令)
--dataset openqa --parallel 16 --number 400真实发载(实测进度 41/400 → 336/400 持续运行)Step 4: 压测窗口内观察 Step 2 抓包(核心观测)
{"model": "qwen", "prompt": "Hello", "max_tokens": 10}(即test_cluster_simple的硬编码签名,与 evalscope 的 openqa 数据集流量截然可分);sleep(1)轮询节拍完全一致;GET /health(每秒轮询)与POST /v1/completions(每秒探针)交替出现;Step 5: 对照(证明非压测流量)
"prompt":"Hello",逐条可分;/v1/completions总数 − evalscope 报告请求数。Step 6(可选,误杀现象): 满负载下探针超时 →
SubprocessError误杀 trial。本次实测未单独复现该分支(探针均 200),维持代码路径证明(scheduler.py:522-528 条件)+ 内部佐证 T3。Expected
运行期状态监控只应读取轻量健康端点(
/health);推理探针仅用于启动就绪判定;探针异常不应左右压测期 trial 成败。Actual
压测全程每秒 1 条
max_tokens=10的探针请求进入服务(真机实测,两种观测通道一致);探针一旦非 200/超时,即使服务本身健康,scheduler 也按服务失败处理终止当轮 trial(代码路径确定)。代码无任何开关可关闭该行为。Root Cause
① 插件把"集群级就绪判定"(需真实推理)直接实现进被 scheduler 高频轮询的
health(),未区分启动阶段与运行阶段;② scheduler 的监控轮询按"是否内置Simulator类"做排除(scheduler.py:520-521),插件模拟器结构化满足SupportsHealth(protocols.py:19-21)且不是Simulator子类,被当作需每秒健康检查的对象;内置 vllm/mindie 模拟器因是该子类被排除——同场景行为不对称。Impact
事实 / 推断 / 待确认
修复方向(供 Issue 讨论)
health()区分阶段:启动阶段(Stage.start)才发推理探针,running 后 N 秒内只查/health(节流缓存最近探针结果);check_success(),让 scheduler 走 benchmark 判定路径,绕开每秒 health 轮询;