4、请求排队问题分析:高并发场景下的vLLM瓶颈、请求排队的原因、排队对推理延迟的影响

4.1 高并发场景下的vLLM瓶颈

说实话,vLLM在单机单卡场景下表现相当亮眼。但一旦进入高并发生产环境,问题就来了。

我遇到过最典型的情况:某天业务方突然说「延迟飙到10秒了」,我上去一看,GPU利用率才60%,但请求队列已经堆了上千条。嗯,这就是典型的vLLM瓶颈——它并不是GPU算力不够,而是调度和内存管理跟不上

具体来说,高并发下vLLM的瓶颈主要集中在三个地方:

  • PagedAttention的内存碎片化:虽然vLLM用PagedAttention解决了显存浪费,但高并发下KV Cache的分配和回收变得频繁,内存碎片反而加剧了。
  • 调度器的单线程瓶颈:vLLM的调度器是单线程的,当请求量上来,调度决策本身就成了瓶颈。
  • Batch Size的天花板:每个推理步能处理的请求数有限,超过这个数就得排队。

核心结论:vLLM的瓶颈不是「算不动」,而是「排不好队」。GPU在等调度,调度在等内存,内存在等回收——整个链路就卡住了。

4.2 请求排队的原因

为什么会排队?说白了就两个原因:资源不够调度策略不合理

4.2.1 资源维度

我习惯把vLLM的资源分为三层:

资源层 瓶颈点 排队表现
GPU显存 KV Cache占满,新请求无法分配 请求等待显存释放
GPU算力 Batch Size打满,无法容纳更多请求 请求等待当前Batch完成
CPU/网络 预处理/后处理线程池满 请求等待CPU处理

你想想看,这三个资源任何一个满了,请求就得排队。而且它们之间还会互相影响——显存不够导致调度变慢,调度变慢导致GPU空闲,GPU空闲又导致吞吐下降,吞吐下降又让队列越堆越长。这就是个恶性循环。

4.2.2 调度策略维度

vLLM默认的调度策略是FCFS(先来先服务),这在高并发下其实挺坑的。我记得有一次线上事故,一个超长文本的请求排在前面,后面几十个短请求全被堵死了。那个长请求跑了30秒,后面所有请求的延迟都变成了30秒+。

我曾经踩过这个坑,后来总结了几种排队原因:

  • 长尾请求阻塞:一个长序列请求占着Batch位置不放,后面的短请求只能干等
  • 优先级缺失:所有请求一视同仁,没有给高优请求插队机制
  • 预填充与解码冲突:预填充阶段需要大量显存,解码阶段需要快速迭代,两者混排时互相拖累

我的经验:在生产环境中,我建议至少实现两级优先级——实时请求和批量请求分开排队。实时请求走快速通道,批量请求走普通通道。这样能避免「一颗老鼠屎坏了一锅粥」。

4.3 排队对推理延迟的影响

排队对延迟的影响,比你想象的要复杂得多。不是简单的「排队时间 + 推理时间」这么简单。

4.3.1 延迟的构成

一个请求从发起到返回,延迟可以拆成四段:

  1. 网络传输延迟:客户端到服务端的往返时间
  2. 排队等待延迟:请求在队列里等待被调度的时间
  3. 预填充延迟:第一次推理计算的时间
  4. 解码延迟:逐token生成的时间

其中,排队等待延迟在高并发下会指数级增长。为什么?因为排队不仅增加了等待时间,还改变了Batch的组成。

4.3.2 排队导致的「雪崩效应」

我举个例子你就明白了:

假设一个GPU能同时处理4个请求。当请求量从4个涨到8个时,排队时间不是翻倍,而是可能翻4倍。原因如下:

  • 第1-4个请求:直接处理,无排队
  • 第5-8个请求:等第1-4个处理完才能开始
  • 但第1-4个请求因为Batch变大,每个请求的处理时间也变长了
  • 于是第5-8个请求的等待时间 = 第1-4个请求的处理时间 × 2

这就是我常说的「排队雪崩」——请求越多,每个请求处理越慢;处理越慢,排队越长;排队越长,延迟越高

注意:这个雪崩效应在vLLM中尤其明显,因为PagedAttention的显存管理在高并发下效率会下降。我曾经在一个压测中看到,当QPS从10涨到20时,P99延迟从200ms直接飙到了2.3s——涨了10倍多。

4.3.3 延迟的量化分析

我习惯用Little定律来估算排队延迟:

L = λ × W

其中:
L = 队列中的平均请求数
λ = 请求到达率(QPS)
W = 平均排队时间

举个例子:如果QPS是20,平均推理时间是500ms,那么队列中的请求数大约是 20 × 0.5 = 10个。每个新请求进来,平均要等前面10个处理完,也就是 10 × 0.5 = 5秒。

嗯,5秒的排队延迟,对于实时推理来说已经不可接受了。

4.4 知识体系图

下面这张图总结了请求排队的核心逻辑:

vLLM请求排队核心逻辑 高并发请求 排队原因 GPU显存不足 KV Cache占满 Batch打满 算力瓶颈 调度策略 FCFS阻塞 排队雪崩效应 请求越多 → 处理越慢 → 排队越长 → 延迟越高 P99延迟飙升 从200ms到2.3s,增长10倍+

4.5 我的建议

面对请求排队问题,我个人的经验是:

  • 不要盲目加GPU:很多时候瓶颈不在算力,而在调度。先优化调度策略,再考虑扩容
  • 监控队列深度:我习惯在Prometheus里加一个队列深度的指标,超过阈值就告警
  • 做请求分级:实时请求和离线请求分开处理,别让离线任务拖垮在线服务

一个小技巧:在K8s中部署vLLM时,我建议用HPA(水平自动扩缩)配合队列深度指标。当队列深度超过10时自动扩容Pod,低于3时缩容。这样能有效缓解排队问题。

好了,关于请求排队的问题就聊到这里。记住一句话:排队不可怕,可怕的是你不知道为什么排队。把原因分析清楚了,解决方案自然就有了。