scheduler耗时过长¶
问题背景¶
在服务化推理场景中,调度器(Scheduler)负责将到达的推理请求按一定策略组Batch并下发到NPU执行。当调度器自身耗时占比过高时,会导致NPU设备空闲等待,整体吞吐下降、请求排队时间增加。在Host Bound场景下(如小模型推理、Decode阶段),单个算子的Host下发时间超过Device执行时间后,调度开销成为系统瓶颈。调度策略配置不当、动态调度优先级切换、组Batch逻辑复杂以及未启用匹配的图模式调度或模型下沉,都会增加scheduler耗时。
问题来源¶
推理
问题现象¶
用户通常先看到推理服务整体吞吐低于预期,NPU利用率偏低但请求排队(waiting)数量持续增长。在Grafana中按调度指标拆开后,常见现象是:
waiting_batch_size指标持续处于高位,而batch_size(running请求数)未达到配置的maxBatchSize上限。- 从
request_status.csv中可观察到大量请求长期处于waiting状态,running状态请求数波动较大。 - NPU执行流上出现间歇性空闲,Timeline视图中连续的Schedule色块之间存在明显的空闲间隙(bubble)。
使用msServiceProfiler采集数据后,在batch.csv中观察到name为batchFrameworkProcessing(组Batch阶段)的during_time(ms)显著偏高,与modelExec(模型执行阶段)耗时之比异常。典型表现为:组Batch耗时占总Batch耗时的比例偏高,而正常场景下该比例通常较低。在Host Bound模型(如小参数量的Encoder模型或Decode阶段的小Batch场景)中尤为明显。
定位过程¶
步骤 1:先确认调度瓶颈是否存在¶
在 Grafana 中查看 batch_size、waiting_batch_size、scheduler:duration、KVCache 水位和 NPU 利用率。调度瓶颈的在线判定条件为:waiting_batch_size 持续增长,scheduler:duration 分位数同步升高,模型执行耗时保持同负载基线,同时 KVCache 未触及容量下限。batch_size 未达到上限和 NPU 利用率低作为旁证。KVCache 水位耗尽时,先按 KV Block 不足案例分析,不能直接归因到调度器。
调度耗时 P99 使用以下查询:
histogram_quantile(
0.99,
sum by (le, instance, dp) (
rate(vllm_profiling_scheduler:duration_bucket[5m])
)
)
模型执行平均耗时使用以下查询:
sum by (instance, dp, phase) (
rate(vllm_profiling_executor:execute_model:duration_sum[5m])
)
/
sum by (instance, dp, phase) (
rate(vllm_profiling_executor:execute_model:duration_count[5m])
)
两个查询使用相同的异常窗口、实例、DP 域和阶段。scheduler P99 上升而模型执行平均耗时稳定,一级定界结论为调度阶段变慢。
步骤 2:用Profiler采集调度阶段数据¶
配置ms_service_profiler_config.json,设置domain为"Schedule; Request; ModelExecute",开启数据采集。采集完成后执行解析命令:
解析生成batch.csv、request.csv、forward.csv、chrome_tracing.json等文件。
步骤 3:分析batch.csv中的调度耗时¶
在batch.csv中筛选name为batchFrameworkProcessing的行,统计其during_time(ms)的分布(平均值、P90、P99)。同时筛选name为modelExec的行,计算组Batch耗时与模型执行耗时的比值。如果组Batch耗时占比偏高,说明调度阶段存在瓶颈。
按dp_rank维度分别统计各DP域的调度耗时,判断是否为特定DP域调度慢。按batch_type(prefill/decode)分别统计,判断是Prefill调度慢还是Decode调度慢。
步骤 4:用服务化拆解工具细粒度拆解Batch执行阶段¶
拆解后查看decode.csv中各子阶段(如数据下发、模型执行、数据接收等)的耗时分布,确认调度阶段的具体耗时瓶颈在哪个子环节。
步骤 5:通过Timeline视图确认bubble位置¶
打开chrome_tracing.json,在Timeline视图中观察Schedule色块与ModelExecute色块之间的时序关系。如果存在大量bubble(空闲间隙),且bubble出现在组Batch阶段而非模型执行阶段,可确认调度器是瓶颈。
结合forward.csv中的bubble_time(ms)字段,统计forward之间的空泡时间。如果空泡时间占比较高,说明调度下发不及时导致NPU等待。
步骤 6:可选使用 Tracing 定位调度 Span¶
需要把阶段结论下钻到具体请求时,在 Jaeger 中使用 Trace ID、request ID 或 Metrics 异常窗口找到目标 Trace。存在正常基线时,选择输入、输出 Token 规模和请求阶段一致的正常 Trace 与异常 Trace,按以下顺序对比:
- 使用
request.id、request.ids或 Span Links 确认 scheduler、model 与目标请求的关联。 - 对比
vllm.scheduler.schedule的时长和batch.request_count、batch.scheduled_tokens属性。 - 对比
vllm.model.execute和vllm_ascend.model_runner.execute的时长。 - 同一 Trace ID 场景直接对比 scheduler 与 model 之间的空白区间;Span Links 场景沿 Link 分别打开关联 Span,不使用两个独立 Trace 的时间差计算空白。
异常观测组的 scheduler Span 稳定高于同负载正常观测组,且 model 与 model runner Span 保持基线时,Tracing 将瓶颈定位在 Scheduler 执行阶段。scheduler Span 本身稳定、但同一 Trace ID 或统一 Perfetto Timeline 中 scheduler 与 model 之间空白增长时,瓶颈位于排队、同步或资源等待,不能输出“Scheduler 自身耗时过长”的结论。
步骤 7:用多维度解析工具获取整体统计¶
查看batch_summary.csv中prefill和decode的batch数量和执行时间统计,从服务整体维度判断调度效率。
问题根因¶
调度器耗时过长的常见根因包括:
-
Host Bound场景:小模型或Decode阶段单算子执行时间极短,但Host调度每个算子的下发流程耗时相对较长,导致Device频繁空闲等待。这是昇腾NPU上Host调度模式的固有问题,可通过CANN的图模式调度或模型下沉调度解决。
-
调度策略配置不当:
maxBatchSize设置过小导致频繁组Batch;动态调度优先级在单并发场景下引入额外的策略切换开销;maxPrefillBatchSize与maxBatchSize配比不合理导致Prefill和Decode调度互相阻塞。 -
组Batch逻辑复杂度过高:请求数量大、请求长度差异大时,调度器需要遍历大量候选请求进行组Batch匹配,匹配算法复杂度随请求数增长。
-
框架适配问题:调度器与昇腾NPU的Task下发机制未充分优化,未启用图模式调度或模型下沉,仍使用单算子模式逐算子下发。
-
资源竞争:调度器线程与其它服务线程竞争CPU资源,导致调度延迟抖动。
解决方法¶
- Host Bound:启用CANN图模式调度或模型下沉,减少Host下发开销。
- 调度策略不当:调整
maxBatchSize和maxPrefillBatchSize配比,关闭不必要的动态调度优先级。 - 组Batch逻辑复杂:优化组Batch算法,减少候选请求遍历范围。
- 框架适配:确认已启用图模式调度或模型下沉,避免单算子模式。
- 资源竞争:确保调度线程有足够CPU资源,避免与其它服务线程竞争。
处理后使用与问题复现时相同的模型、版本、并发、输入/输出 Token 分布和服务参数复测。以下条件全部满足,处理结果才通过验证:
scheduler:durationP99 和batchFrameworkProcessingP99 回到同负载基线范围。waiting_batch_size不再持续增长。vllm.scheduler.scheduleSpan 与同一时间线中的调度空白区间恢复到基线。- 模型执行耗时没有增加,NPU 利用率和吞吐恢复。
- TTFT、TPOT、错误率和显存没有回退。
定位方法论总结¶
本案例展示的是联合分析路径:先用 ms-service-metric 确认 waiting 增长、scheduler:duration 升高、模型执行稳定且 KVCache 容量正常;再用 Tracing 将目标请求定位到 vllm.scheduler.schedule,并排除 model 和 model runner 执行变慢;然后用 msServiceProfiler 的 batch.csv 对比组 Batch 耗时与模型执行耗时,使用统一 Timeline 确认调度空白区间。只使用 Metrics 时可以输出总体调度阶段结论,只使用 Tracing 时可以输出目标请求的调度路径结论;三类数据一致时可以同时确认影响范围、请求路径和设备时间线。
核心判断逻辑:如果组Batch耗时占比高且Timeline上存在大量调度间隙,则瓶颈在调度器;如果模型执行耗时占比高,则瓶颈在模型侧。
对工具的改进建议¶
ms-service-metric¶
当前在线监控已能查看waiting_batch_size、batch_size等调度指标。建议增加调度效率指标,如"调度耗时/模型执行耗时"比值、"平均组Batch延迟"等,便于在线快速识别调度瓶颈。增加Host Bound风险提示,当检测到小模型或Decode阶段NPU利用率持续偏低时,自动提示可能存在Host Bound。
msServiceProfiler¶
当前Profiler已能通过batch.csv对比组Batch耗时与模型执行耗时。建议在batch.csv中增加调度子阶段拆解字段,如"请求匹配耗时"、"Token分配耗时"、"Task下发耗时"等,便于直接定位调度瓶颈子环节。在Timeline视图中增加调度效率面板,自动计算并展示组Batch耗时占比、bubble占比等关键指标。
服务化拆解工具¶
当前拆解工具需要手动指定batch_size或rid。建议增加自动识别耗时异常Batch的能力,自动选取耗时最长的Top N个Batch进行拆解分析。