记录一下那天晚上的排查过程。连续批处理里一个 8000 token 的长请求和十几个 200 token 的短请求组在同一批,短请求要等整批解码完才返回,实测短请求首字 15 秒,长请求自己只用了 6 秒。

刚开始盯着「max-num-seqs 只看条数,不看各自的剩余长度」,折腾了半个多小时,排掉了。

把日志和配置对完,能解释这个现象的基本就这几处。批内同步推进,最慢的序列决定整批结束时间。还有一种是没有 token 级的提前退出,短序列算完仍占着批位。

不容易想到的是,调度器没有按剩余 token 数排序。

动手时先按长度分桶统计首字等待

python agg.py --log req.log --field ttft --group len_bucket

限制单批内允许的最大长度差

python -c "print('max_len_ratio=4')"

然后开启分块预填充让短请求先出头

python -m vllm.entrypoints.openai.api_server --model Qwen/Qwen2.5-7B-Instruct --enable-chunked-prefill

末了按长短一比十压测看尾延迟

python bench_mix.py --long 1 --short 10 --duration 180

怎么算真的好了,看的是同一批现象。短请求首字 P99 从 15 秒降到 3 秒以内,长请求总时长基本不变,批内长度差被限制在设定倍数内。

提醒一点。短请求的体验决定整体观感,长文生成单独走一条队列,比在同一个批里做公平调度更简单有效。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189