2. vLLM基础架构

核心组件:vLLM的五大支柱

vLLM之所以能在众多推理引擎中脱颖而出,源于其围绕PagedAttention设计的组件化架构。理解这些组件,是后续调优调度参数的前提。下图展示了vLLM处理请求时的核心组件与数据流转关系。

vLLM 核心组件与请求处理流水线 客户端请求 /v1/completions LLM Engine 请求入口 · 参数校验 Scheduler 调度策略 · 连续批处理 max_num_seqs / max_seq_len Worker / Model Runner GPU 执行 · 张量并行 · 流水线并行 KV Cache Manager PagedAttention 输出采样与去重 temperature / top_p / top_k / logits 处理 显存管理 物理块 0 物理块 1 物理块 2 物理块 3 物理块 4 物理块 5 Block Manager 按需分配 · 引用计数 Prefix Caching 映射 关键数据流: ① 请求 → LLM Engine 校验 → Scheduler 决定批次 ② Scheduler 将序列分配到 Worker,KV Cache Manager 分配物理块 ③ PagedAttention 在非连续物理块上执行注意力计算 ④ 采样输出 → 返回客户端,同时释放不再需要的 KV 块

vLLM的架构可拆解为五个核心组件,它们各司其职又紧密协作:

  • LLM Engine(引擎层):对外提供OpenAI兼容的HTTP接口,负责请求校验、参数解析和结果返回。它是用户与系统交互的唯一入口。
  • Scheduler(调度器):vLLM的“大脑”,决定哪些序列进入本轮迭代、以何种顺序执行。它实现了连续批处理(Continuous Batching),即每步迭代后动态调整批次,而非等待整个序列生成完毕。
  • Worker / Model Runner(执行层):真正调用GPU执行Transformer前向传播的模块。在多卡场景下,它负责张量并行(Tensor Parallelism)和流水线并行(Pipeline Parallelism)的协调。
  • KV Cache Manager(缓存管理器):管理GPU显存中的KV缓存块。它维护物理块与逻辑块的映射关系,并记录每个块的引用计数,以便及时释放不再使用的缓存。
  • PagedAttention(分页注意力):vLLM的核心创新。它将连续的KV缓存拆分为固定大小的“块”(Block),允许这些块在显存中非连续存放,从而消除显存碎片,将显存利用率提升至接近90%。

推理流程:一次请求的完整旅程

理解vLLM的推理流程,是掌握调度参数作用点的关键。整个流程可划分为预填充(Prefill)和解码(Decode)两个阶段,调度参数在这两个阶段的作用截然不同。

  1. 请求接入与预处理:客户端发送请求后,LLM Engine将输入文本转换为Token ID序列,并记录序列的元信息(如长度、采样参数)。
  2. 调度决策(Prefill阶段):Scheduler根据当前等待队列、显存余量以及max_num_seqs、max_seq_len等参数,决定将哪些新请求纳入本批次。此阶段需要为每个序列分配足够的KV块来缓存整个输入上下文的注意力结果。
  3. 预填充计算:Worker对批次内所有请求的输入Token并行执行前向传播,生成第一个输出Token,并填充KV Cache。此阶段计算密集,GPU利用率高。
  4. 调度决策(Decode阶段):每生成一个Token后,Scheduler会重新评估批次。已生成完毕的序列会被移出,新到达的请求可能被加入。此时max_num_seqs决定了并发解码的上限。
  5. 解码迭代:对批次内每个序列,模型读取其最后一个Token的Embedding,结合KV Cache执行注意力计算,预测下一个Token的概率分布。随后根据temperature、top_p等采样参数选出最终Token。
  6. 流式返回与资源释放:生成的Token通过流式接口逐步返回给客户端。当序列遇到结束符或达到max_tokens限制时,其占用的KV块被释放,供新请求使用。

调度参数作用点速查

参数名 作用阶段 核心影响
max_num_seqs Prefill + Decode 限制批次内最大序列数,直接影响吞吐与显存峰值
max_seq_len 请求准入 超过该长度的请求直接报错,防止显存溢出
gpu_memory_utilization 启动时 决定KV Cache可用显存上限,影响可并发序列总量
block_size KV Cache分配 每个物理块容纳的Token数,影响显存碎片程度
max_num_batched_tokens Prefill 限制单次预填充的Token总数,防止长输入导致OOM

对比分析:vLLM vs. TensorRT-LLM vs. HuggingFace TGI

在实际选型中,工程师常将vLLM与TensorRT-LLM、TGI(Text Generation Inference)对比。三者目标一致——提升推理性能,但设计哲学差异显著。

维度 vLLM TensorRT-LLM HuggingFace TGI
核心优化 PagedAttention + 连续批处理 图优化 + 算子融合 + 量化 连续批处理 + 张量并行
显存管理 分块KV Cache,利用率高 静态显存池,需精确计算 动态分配,碎片较多
易用性 Python原生,开箱即用 需编译引擎,学习曲线陡 Python友好,部署简单
量化支持 GPTQ / AWQ / FP8 INT4/INT8/FP8,支持最全 GPTQ / AWQ
动态批处理 迭代级调度,粒度最细 请求级调度,粒度较粗 迭代级调度
适用场景 高并发在线服务 极致性能、生产环境 快速原型、中小规模

从实际测试数据看,在A100上使用Llama-2-7B模型、并发32路请求时,vLLM的吞吐量可达TGI的2.2倍左右,而TensorRT-LLM在静态batch下可能比vLLM再快10%~15%,但其代价是需要针对具体模型和GPU进行编译优化,且动态请求场景下优势会缩小。vLLM的优势在于动态调度灵活性和部署便捷性,特别适合请求长度波动大、并发数高的在线场景。

案例:从TGI迁移到vLLM的收益

某智能客服团队原先使用TGI部署Qwen-14B模型,线上峰值时平均首Token延迟(TTFT)达到1.8秒,GPU显存利用率仅62%。迁移到vLLM后,仅调整了gpu_memory_utilization=0.90和max_num_seqs=64,在相同硬件上取得了以下效果:

  • TTFT降至0.9秒,降低50%
  • 吞吐量从每秒120个Token提升至310个Token
  • 显存利用率稳定在85%以上,未出现OOM

这一提升主要归功于PagedAttention消除了KV Cache碎片,以及迭代级调度让GPU始终在处理有效请求,而非等待慢序列完成。

误区与复盘:调度参数不是越大越好

在调优过程中,工程师常陷入以下误区:

误区一:盲目调大 max_num_seqs

增大并发序列数确实能提升吞吐,但会线性增加KV Cache占用。当显存不足时,vLLM会触发显存交换(Swap)到CPU,导致解码速度骤降。正确做法是监控vllm:num_requests_running和vllm:gpu_cache_usage_perc指标,将缓存使用率维持在90%~95%之间。

误区二:忽略 max_num_batched_tokens 对长输入的影响

当多个长文档同时到达时,Prefill阶段的Token总数可能瞬间超过GPU计算能力。若该参数设置过大,会导致单次前向传播时间过长,阻塞后续解码。建议根据模型最大序列长度和GPU算力,将max_num_batched_tokens设为max_num_seqs × 平均输入长度的1.2倍左右。

复盘建议:每次调整参数后,应同时观察TTFT、ITL(Token间延迟)和吞吐量三个指标。TTFT反映Prefill效率,ITL反映Decode稳定性,吞吐量反映整体利用率。三者不可兼得时,需根据业务优先级取舍——对话场景优先降低TTFT,离线批量生成则更看重吞吐。