4、vLLM核心架构总览:PagedAttention、Continuous Batching、分布式推理等核心组件
vLLM 之所以能在众多 LLM 推理框架中脱颖而出,核心在于它对传统推理系统的三个关键瓶颈——显存管理、调度效率和跨卡扩展——进行了架构级重构。本章将深入剖析 vLLM 的三大支柱:PagedAttention 显存管理、Continuous Batching 动态调度以及分布式推理引擎,帮助您建立对 vLLM 内部工作机制的系统性认知,为后续的性能调优打下坚实基础。
4.1 PagedAttention:显存管理的分页革命
核心原理
传统推理框架(如 HuggingFace Transformers)在生成前会为每个请求的 KV Cache 预分配连续显存空间,且按最大序列长度预留。这导致两个严重问题:一是显存碎片化,不同请求的 KV Cache 大小不一,难以紧凑排列;二是预分配浪费,实际生成长度远小于最大长度时,大量显存闲置。PagedAttention 借鉴操作系统虚拟内存的分页思想,将 KV Cache 划分为固定大小的物理块(Block),每个块通常可存储 16 或 32 个 token 的 KV 向量。逻辑上连续的 KV Cache 在物理显存中可以不连续,通过块表(Block Table)维护映射关系。
| 对比维度 | 传统 KV Cache | PagedAttention |
|---|---|---|
| 显存分配粒度 | 按请求整体预分配 | 按块(Block)按需分配 |
| 显存利用率 | 通常 40%-60% | 可达 90% 以上 |
| 碎片处理 | 无法避免外部碎片 | 块级紧凑管理 |
| 共享支持 | 不支持跨请求共享 | 支持 Prefix 共享(如 System Prompt) |
| 扩容方式 | 需整体迁移 | 追加新块即可 |
判断方法与操作流程
在实际部署中,判断 PagedAttention 是否生效,可通过 vLLM 的 --enable-prefix-caching 参数开启前缀缓存,并观察 vllm serve 启动日志中的显存统计。若日志显示 GPU KV cache size: 2048 blocks 且每个 block 大小固定,说明分页机制已启用。调优时,可通过 --block-size 参数调整块大小(默认 16),块越小显存利用率越高,但块表开销增大;块越大则相反。
--enable-prefix-caching,系统提示词(System Prompt)的 KV Cache 可被所有会话共享,显存节省可达 30%-50%。
案例拆解:显存碎片化问题定位
某团队部署 Llama-3-8B 时,发现并发 32 个请求后 GPU 显存溢出(OOM),但 nvidia-smi 显示显存利用率仅 55%。通过 vLLM 的 /metrics 端点查看 vllm:num_requests_running 和 vllm:gpu_cache_usage_perc,发现 cache 使用率已达 98%,但实际 token 生成量远未达到模型容量。分析根因:默认 block-size=16 对于短请求(平均 50 token)造成块内碎片,每个块平均浪费 6 个 token 空间。将 block-size 调整为 8 后,cache 使用率降至 82%,并发能力提升至 48 个请求。此案例说明,块大小需根据实际请求长度分布动态调整。
4.2 Continuous Batching:迭代级动态调度
核心原理
传统 Batching 以"请求级"为单位:一个 batch 必须等所有请求完成生成后才释放 GPU 资源,导致短请求被长请求阻塞,GPU 利用率波动大。Continuous Batching(连续批处理)将调度粒度细化到"迭代级"(即每个 token 生成步骤)。调度器在每个迭代结束后,立即将已完成的请求移出 batch,并插入新到达的请求。这样 GPU 始终在处理活跃请求,消除了等待空隙。
调度策略与参数
- 抢占策略:当显存不足时,vLLM 会抢占(Preempt)低优先级请求,将其 KV Cache 换出到 CPU 或丢弃,优先保证高优先级请求。
- 最大批大小:通过
--max-num-seqs控制单次迭代最多处理的序列数,默认 256。增大该值可提高吞吐,但会增加延迟。 - 动态批组成:调度器根据当前显存余量、请求到达率、各请求已生成长度,动态决定下一迭代的 batch 组成。
案例拆解:混合负载下的调度优化
某在线服务同时处理两类请求:A 类为短问答(平均 30 token),B 类为长文档摘要(平均 800 token)。使用传统 Batching 时,A 类请求平均等待 4.2 秒,用户体验差。切换到 vLLM 后,通过 --max-num-seqs 128 和 --max-paddings 4 配置,A 类请求平均等待降至 0.8 秒,B 类请求吞吐提升 20%。进一步分析发现,调度器默认采用 FCFS(先来先服务)策略,导致长请求占用 batch 时间过长。通过自定义调度策略(基于剩余长度预估),将 A 类请求优先调度,整体 P95 延迟下降 35%。
vllm:num_requests_running 与 vllm:num_requests_waiting 的比值。若 waiting 长期大于 running,说明调度器吞吐不足,可增大 max-num-seqs;若 running 中大量请求处于 preempt 状态,说明显存不足,需优化 KV Cache 或增加 GPU。
4.3 分布式推理:从单卡到多卡集群
核心原理
当单卡显存无法容纳模型权重或 KV Cache 时,vLLM 通过分布式推理将模型切分到多张 GPU。支持三种并行策略:张量并行(TP)将单个 Transformer 层的权重按行/列切分到多卡,适合单机多卡;流水线并行(PP)按层切分,不同卡负责不同层,适合多机;专家并行(EP)用于 MoE 模型,将不同专家分配到不同卡。vLLM 底层使用 Ray 或原生 NCCL 进行通信,对上层 API 完全透明。
| 并行策略 | 切分粒度 | 通信开销 | 适用场景 |
|---|---|---|---|
| TP | 权重矩阵 | 高(每层 AllReduce) | 单机 2-8 卡 |
| PP | Transformer 层 | 低(仅层间传输) | 多机,跨节点 |
| EP | MoE 专家 | 中(路由通信) | MoE 模型(如 Mixtral) |
操作流程与配置
# 单机 4 卡张量并行启动
vllm serve meta-llama/Llama-3-70B \
--tensor-parallel-size 4 \
--max-num-seqs 64
# 多机流水线并行(需 Ray 集群)
ray start --head --port=6379
vllm serve meta-llama/Llama-3-70B \
--pipeline-parallel-size 2 \
--tensor-parallel-size 4
案例拆解:70B 模型多卡部署
某企业需部署 Llama-3-70B(约 140GB 权重),单卡 A100-80G 无法加载。初始方案使用 TP=2(2 张 A100),但吞吐仅 120 tokens/s,且 GPU 利用率不均(卡 0 利用率 95%,卡 1 仅 60%)。通过 nsys profile 分析发现,AllReduce 通信占比达 40%,瓶颈在 NVLink 带宽。优化方案:改用 TP=4(4 张 A100),虽然单卡显存利用率下降,但通信并行度提升,吞吐增至 280 tokens/s。进一步开启 --enable-chunked-prefill 将长 prompt 分块处理,避免 prefill 阶段阻塞 decode,最终吞吐稳定在 350 tokens/s。
4.4 核心组件协同与性能调优总览
组件间依赖关系
三个核心组件并非独立工作:调度器(Continuous Batching)决定哪些请求进入执行,PagedAttention 为这些请求分配显存块,分布式引擎则负责将计算任务分发到多卡。任一组件成为瓶颈都会拖累整体性能。例如,若 PagedAttention 的块表查询延迟过高,即使调度器分配了足够的 batch,GPU 也会因等待显存寻址而空闲。
性能调优决策树
- 观察指标:首先查看
vllm:gpu_cache_usage_perc和vllm:num_requests_running。 - 显存瓶颈:若 cache 使用率 >90% 且 running 请求少,优先优化 PagedAttention(调整 block-size、开启 prefix-caching)。
- 计算瓶颈:若 GPU 利用率 >95% 但吞吐低,检查是否 TP 配置不当或模型计算密集。
- 调度瓶颈:若 waiting 队列持续增长,增大 max-num-seqs 或优化调度策略。
总结复盘
vLLM 的架构设计体现了"以显存为中心"的推理优化理念。PagedAttention 解决了显存碎片化,Continuous Batching 解决了计算空闲,分布式推理解决了单卡容量限制。三者协同使得 vLLM 在同等硬件下吞吐量可达传统框架的 2-4 倍。实际调优时,务必先定位瓶颈类型(显存/计算/通信/调度),再针对性调整参数,避免盲目堆叠配置。