事情本身不复杂,线索都在日志里。A10 24G 单卡起 vLLM 0.6.3 跑 Qwen2.5-7B-Instruct,压测脚本把并发从 8 拉到 64,首 token 等待从 380ms 一路涨到 4.1 秒,nvidia-smi 只看得到显存用到 21G,GPU 利用率 92%,max-num-seqs 还是默认值。
第一反应是「客户端没有限制在途请求,压测脚本把 64 个流同时挂在同一个连接池上」,验证下来不成立。
原因不止一个,得分开看。连续批处理里排队长度超过 max-num-seqs,新请求只能等前面整批解码完。少数情况下是默认 block size 16 让 KV cache 碎片多,长请求一进来就挤掉短请求。
另外,首 token 的时间被 prefill 排队吃掉,而 decode 阶段算力反而闲着。
上来先把引擎的批处理参数显式写进启动命令再压一次
python -m vllm.entrypoints.openai.api_server --model Qwen/Qwen2.5-7B-Instruct --max-num-seqs 32 --max-model-len 8192 --gpu-memory-utilization 0.88
压测时只跑 16 并发,看 TTFT 是否回到 1 秒以内
python bench_ttft.py --concurrency 16 --stream --url http://127.0.0.1:8000/v1/chat/completions
接着用官方 metrics 把 waiting 队列单独拉出来看
curl -s http://127.0.0.1:8000/metrics | grep -E 'vllm:num_requests_(waiting|running)'
等前面都确认过,再按 queue 长度做准入,超过阈值直接返回 429
python gate.py --max-waiting 24 --listen 8001 --upstream 127.0.0.1:8000
恢复的判定其实很直接。同样并发下 vllm:num_requests_waiting 长时间停在十几以内,TTFT 的 P99 稳定在 1.2 秒以下,而 num_requests_running 与 –max-num-seqs 对得上。
把并发数当成吞吐指标是最常见的误判,排队长度和 KV cache 块数才是决定首 token 的两个量,先看 waiting 再谈扩容。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
