事情本身不复杂,线索都在日志里。vLLM 0.6.6 起 Qwen2.5-14B-Instruct,max_num_seqs 设三十二,短请求的首字延迟在三百到九百毫秒之间跳,同一批输入重复压测方差很大;关掉抢占之后抖动变小,但吞吐掉了一半。
第一反应是「chunked prefill 的块大小和并发不匹配」,验证下来不成立。
原因不止一个,得分开看。批内混入长序列,短请求要等长请求算完。少数情况下是KV cache 不够触发抢占与重算。
少数情况下是客户端并发不稳定,实际批量一直在变。
上来先看服务端各分位延迟与运行中的请求数
curl -s http://vllm:8000/metrics | Select-String 'time_to_first_token|num_requests_running'
固定并发重测排除客户端干扰
python bench.py --concurrency 8 --requests 200 --stream --report p50,p95,p99
接着按显存重算 KV cache 能撑多少并发
python -c "print((24-14*2)*1024**3//(2*28*128*2*4096))"
调低并发上限再复测一轮
python -m vllm.entrypoints.openai.api_server --model Qwen2.5-14B-Instruct --max-num-seqs 16 --gpu-memory-utilization 0.9
怎么算真的好了,看的是同一批现象。固定八个并发下 P50 与 P99 的首字延迟差值收敛到一百五十毫秒以内,抢占计数不再增长,吞吐仍在可接受范围。
这里还有个坑。首字延迟抖动多半来自批内长短请求互相等待,先把并发固定住再看服务端指标,比直接调参数有效。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
