4. vLLM初识

当我们把大语言模型(LLM)从训练环境迁移到生产环境时,面临的第一个核心问题就是:如何让模型在有限的GPU资源下,以更低的延迟、更高的吞吐量为尽可能多的用户请求服务。传统的推理框架(如简单的Transformers库直接推理)往往存在显存利用率低、请求排队严重、并发能力差等痛点。vLLM正是为解决这些问题而生的高性能推理引擎。本章将深入剖析vLLM的本质、其两大核心特性——PagedAttention与Continuous Batching,并通过与主流框架的对比,帮助你建立选型与技术判断的基准。

vLLM 核心架构与特性关系图 用户请求流 多用户并发 / 流式输出 调度器 (Scheduler) Continuous Batching 决策 KV Cache 管理器 PagedAttention 显存分配 GPU 计算核心 注意力计算 / 前馈网络 GPU 显存池 逻辑块 → 物理块映射 块1 (16 slots) 块2 (16 slots) 块3 (16 slots) 块N ... PagedAttention Continuous Batching 高吞吐 / 低延迟输出 流式返回 / 批量完成 对比维度 吞吐 / 显存 / 易用性 生态 / 高级特性

上图清晰地展示了vLLM的内部工作逻辑:用户请求进入调度器,调度器基于Continuous Batching策略决定哪些请求的哪些可以立即被GPU计算;同时,KV Cache管理器通过PagedAttention机制,将显存中的KV缓存划分为固定大小的“块”,并维护逻辑块到物理块的映射。这种设计使得显存利用率极高,且多个请求可以交错执行,从而实现了吞吐量的飞跃。

4.1 核心原理:为什么传统推理框架难以支撑高并发?

在深入vLLM之前,我们需要理解传统推理框架(如HuggingFace Transformers + PyTorch)在处理并发请求时的瓶颈。传统方式通常采用“静态批处理”(Static Batching)或“简单排队”策略。

传统推理的显存浪费与排队困境

假设我们有一个7B参数的模型,在FP16精度下,模型权重约占14GB显存。对于每个请求,模型需要生成KV Cache(键值缓存)。在传统实现中,KV Cache的大小是根据请求的最大生成长度预先分配的。例如,如果设置最大生成长度为1024个,每个的KV Cache需要约0.5MB(具体取决于层数和头数),那么每个请求将预分配约512MB显存。如果实际只生成了100个就结束了(如用户提前停止),那么剩余的924个的显存空间就被白白浪费了。

更糟糕的是,当多个请求并发到达时,传统框架要么将它们排队逐个处理(导致GPU利用率极低),要么将它们组成一个静态batch。静态batch的缺点是:batch中所有请求必须等待最慢的那个请求完成才能释放资源,这被称为“集体等待”问题。例如,一个batch中有4个请求,生成长度分别为50、100、200、500个,那么GPU需要等待500个的请求完成后,才能释放整个batch的显存,导致前三个请求的完成时间被严重拖后。

vLLM通过两项关键创新解决了上述问题:PagedAttention 解决了显存碎片化和预分配浪费问题;Continuous Batching 解决了集体等待和GPU空转问题。

4.2 核心特性一:PagedAttention——操作系统的虚拟内存思想

PagedAttention的灵感来源于操作系统的虚拟内存分页机制。在传统推理中,KV Cache被存储在连续的内存空间中,这会导致两个问题:一是显存碎片化(不同请求的KV Cache大小不一,难以找到连续大块内存);二是预分配浪费(为了满足最大长度,必须预留大量空间)。

PagedAttention将KV Cache划分为固定大小的块(Block),每个块可以存储固定数量的KV状态(例如,每个块存储16个的KV)。每个请求的KV Cache不再需要连续的内存,而是由多个逻辑块组成,这些逻辑块通过块表映射到物理显存块。

对比维度 传统连续内存管理 PagedAttention 块管理
显存分配单位 按请求最大长度预分配连续空间 按需分配固定大小的块(如16 /块)
显存利用率 通常只有60%-70%(存在大量内部碎片) 可接近100%(仅分配实际使用的块)
共享支持 不支持跨请求共享KV Cache 支持(如并行采样时多个输出共享Prompt的KV)
内存碎片 存在外部碎片和内部碎片 无外部碎片,内部碎片最多浪费一个块

这种设计带来的直接收益是:显存利用率提升了数倍。在相同的GPU显存下,vLLM可以并发处理更多的请求。例如,在A100 40GB显卡上,使用传统方式可能只能并发处理10个请求(每个请求预分配4GB KV Cache),而使用vLLM,由于按需分配,可能可以处理30-50个请求(取决于实际生成长度分布)。

经验提示:在实际部署中,PagedAttention的块大小(--block-size参数,默认16)是一个可调参数。块越小,显存利用率越高,但块表管理开销越大;块越大,管理开销小,但内部碎片可能增多。对于生成长度较短的场景(如分类任务),建议使用较小的块(如8);对于长文本生成(如文章写作),默认16或32表现更佳。

4.3 核心特性二:Continuous Batching——动态调度与交错执行

Continuous Batching(连续批处理)打破了传统静态batch的“集体等待”限制。其核心思想是:当一个请求完成生成时,立即从等待队列中拉入一个新请求,填充到batch的空闲位置中。更精细地,vLLM在级别进行调度:在每个解码步骤,调度器决定哪些请求的哪些可以执行。

具体流程如下:

  1. 迭代级调度:vLLM在每个forward pass(迭代)之前,检查所有正在运行的请求和等待队列。
  2. 抢占与恢复:如果显存不足,vLLM会暂停(抢占)某些请求(将其KV Cache换出到CPU),腾出空间给新请求。当显存充足时,再恢复被抢占的请求。
  3. 动态batch组成:每个迭代的batch组成都是动态的。例如,迭代1处理请求A、B、C;迭代2中,请求A已完成,则加入请求D,batch变为B、C、D。

这种机制带来的性能提升是显著的。根据vLLM官方论文和实测数据,相比传统静态batching,Continuous Batching可以将吞吐量提升2-4倍,尤其是在请求生成长度差异较大的场景下。

案例拆解:混合负载下的吞吐量对比

背景与约束:某SaaS平台需要部署一个6B参数的对话模型,使用1张A10 24GB GPU。业务特点是:20%的请求是短问答(平均生成50 ),80%的请求是长文本总结(平均生成300 )。

初始现象:使用传统Transformers库的静态batching,设置max_length=512,batch_size=8。实测吞吐量仅为120 tokens/s,GPU利用率约45%。短问答请求的平均响应时间高达8秒(因为要等待长文本请求完成)。

分析判断:问题在于静态batch的集体等待效应。长请求拖慢了短请求,且预分配的KV Cache浪费了约40%的显存。

实际操作:切换到vLLM,设置--max-num-seqs=16(最大并发序列数),启用Continuous Batching。未调整其他参数。

结果对比:吞吐量提升至480 tokens/s(提升4倍),GPU利用率升至92%。短问答的平均响应时间降至1.2秒,长文本请求的响应时间也因整体排队减少而略有改善。

风险与代价:vLLM的调度器会占用少量CPU资源(约1-2核),且需要额外的显存用于块表管理(约占总显存的1%-2%)。此外,如果请求的到达速率极不均匀(突发流量),需要配合请求级排队策略(如加一层负载均衡)来避免队头阻塞。

复盘经验:对于混合长度负载,vLLM的Continuous Batching是“开箱即用”的优化。但要注意监控--max-num-seqs参数,设置过大会导致显存不足(OOM),设置过小则无法充分利用GPU并行能力。建议从默认值开始,逐步调大,观察GPU显存利用率和吞吐量的变化曲线。

4.4 与其他推理框架的对比与选型

目前主流的LLM推理框架除了vLLM,还有HuggingFace TGI(Text Generation Inference)、NVIDIA TensorRT-LLM、以及LightLLM等。选择哪个框架取决于你的具体场景:是追求极致吞吐、低延迟,还是需要灵活的模型支持。

框架 核心优势 显存优化机制 适用场景 学习曲线
vLLM 吞吐量极高,易用性好(兼容HuggingFace模型),社区活跃 PagedAttention + Continuous Batching 高并发API服务、多用户SaaS、需要快速部署的场景 低(pip install vllm即可)
TGI HuggingFace官方支持,功能全面(支持量化、流式输出) Static Batching + 显存优化(但不如vLLM激进) 与HF生态深度集成、需要模型微调后快速上线的场景 低
TensorRT-LLM 延迟极低,GPU利用率最高(NVIDIA深度优化) 图优化 + 自定义KV Cache管理 对延迟要求极高的生产环境(如实时交互)、有NVIDIA工程团队支持 高(需要模型编译、转换)
LightLLM 轻量级,支持多GPU流水线并行 基于vLLM思想但更轻量 资源受限的边缘部署、需要极致轻量化的场景 中

从上面的对比可以看出,vLLM在“易用性”和“吞吐量”之间取得了最佳平衡。TensorRT-LLM虽然性能上限更高,但需要将模型转换为TensorRT引擎格式,且对模型结构的支持有限(某些自定义算子可能不支持)。TGI的吞吐量通常比vLLM低20%-30%,但胜在功能全面(如内置推理端点、模型并行等)。

风险提示:不要盲目追求“吞吐量最高”而选择TensorRT-LLM。如果你的团队没有NVIDIA的深度技术支持,且模型迭代频繁(每周更新),TensorRT-LLM的模型编译时间(通常需要30分钟到1小时)会成为开发瓶颈。vLLM支持热加载新模型,无需编译,更适合快速迭代的研发环境。

4.5 常见误区与总结复盘

在初次使用vLLM时,开发者常陷入以下几个误区:

  • 误区一:认为vLLM只支持特定模型。实际上,vLLM支持所有HuggingFace格式的模型(包括Llama、Mistral、Qwen、ChatGLM等),只需通过--model参数指定路径即可。
  • 误区二:忽略--gpu-memory-utilization参数。该参数控制vLLM使用的显存比例(默认0.9)。如果设置过高,可能导致KV Cache预留不足,触发频繁的抢占;设置过低,则浪费显存。建议根据实际负载调整,观察vllm日志中的KV Cache使用率。
  • 误区三:混淆“吞吐量”与“延迟”。vLLM优化的是吞吐量(每秒生成的数),对于单个请求的延迟(首延迟),vLLM与TensorRT-LLM相比并无明显优势。如果你的场景是单用户交互(如聊天机器人),延迟更重要;如果是离线批量处理,吞吐量更重要。

总结复盘:vLLM的核心价值在于通过PagedAttention和Continuous Batching,将GPU显存利用率从60%提升至95%以上,将吞吐量提升2-4倍。在选型时,建议遵循以下决策路径:

  1. 如果追求快速部署和高吞吐,且模型是主流架构,首选vLLM。
  2. 如果延迟敏感(如实时语音交互),且GPU资源充足,考虑TensorRT-LLM。
  3. 如果模型结构特殊(如多模态模型),先检查vLLM的官方支持列表,若不支持则退回TGI。