vLLM基础架构:核心组件、推理流程与关键性能指标
在诊断吞吐瓶颈之前,必须先建立对 vLLM 内部工作方式的清晰认知。vLLM 并非简单的模型封装,而是一套围绕 PagedAttention 设计的连续批处理推理引擎。理解其核心组件如何协作、请求如何流转、以及哪些指标真正反映性能,是后续所有调优动作的前提。
2.1 核心组件与职责边界
vLLM 的架构可以拆解为四个相互协作的层次,每一层都对应着吞吐优化中的关键杠杆。
核心组件总览
- LLM Engine(引擎层):对外提供
generate()接口,负责接收请求、管理输出流,是用户与系统交互的唯一入口。 - Scheduler(调度器):vLLM 的“大脑”。它决定每一轮迭代(step)中哪些序列(sequence)被送入模型执行,并管理 KV Cache 的物理块分配与释放。
- Block Manager / PagedAttention(显存管理器):将 KV Cache 划分为固定大小的物理块(默认 16 tokens/块),通过块表实现逻辑连续、物理离散的显存管理,这是 vLLM 高吞吐的基石。
- Model Executor(模型执行器):负责将调度器选中的序列批量打包(batching),调用底层 GPU Kernel(如量化算子、FlashAttention)完成前向计算。
这四个组件在每次推理迭代中形成闭环:调度器决定“做什么”,显存管理器决定“放哪里”,模型执行器负责“算出来”,引擎层负责“传出去”。
2.2 推理流程:从请求到 Token 流
vLLM 的推理流程与传统的“一次性生成”不同,它采用 迭代级调度(Iteration-level Scheduling)。这意味着模型每前向一次(一个 decode step),调度器都会重新评估所有在途序列的状态,决定是否继续、暂停或加入新请求。
一个典型请求的生命周期如下:
- 预填充(Prefill)阶段:客户端发送完整提示词(Prompt),vLLM 将其切分为 Token 序列。此阶段并行处理整个提示词,计算并存储首个 Token 的 KV Cache。这是计算密集型阶段,耗时与提示词长度成正比。
- 解码(Decode)阶段:模型逐 Token 生成输出。每步只输入上一步生成的 1 个 Token,同时从 KV Cache 中读取历史信息。这是内存带宽密集型阶段,也是吞吐瓶颈的主要发生地。
- 调度介入:在每步 decode 前,Scheduler 检查所有序列的状态。若某序列已生成完毕(遇到 EOS 或达到最大长度),则释放其占用的物理块;若有新请求到达且显存充足,则将其加入当前批次。
- 输出流式返回:生成的 Token 通过 Engine 层以流式(streaming)方式返回给客户端,用户无需等待全部生成完毕即可看到首字。
关键认知:vLLM 的吞吐优势并非来自“一次处理更多请求”,而是来自“每一步都让 GPU 尽可能满载”。连续批处理让不同请求处于各自生命周期的不同阶段,从而在时间维度上填满计算间隙。
2.3 关键性能指标:定义与解读
要诊断吞吐瓶颈,必须先明确“吞吐”的度量方式。vLLM 官方及业界常用的指标如下,它们从不同维度反映系统效率。
| 指标 | 定义 | 反映的问题 | 调优关联 |
|---|---|---|---|
| 吞吐量(Throughput) | 每秒生成的 Token 总数(输出 tokens/秒) | 系统整体处理能力 | 受 batch size、显存容量、算子效率影响 |
| 首 Token 延迟(TTFT) | 从请求发出到收到第一个输出 Token 的时间 | 用户等待的第一印象 | 受 Prefill 阶段计算量、队列排队影响 |
| 单 Token 延迟(ITL) | 相邻两个输出 Token 之间的时间间隔 | 流式输出的流畅度 | 受 decode 阶段 batch size 与显存带宽影响 |
| KV Cache 利用率 | 已分配的物理块 / 总可用物理块 | 显存是否被有效使用 | 受块大小、调度策略、请求长度分布影响 |
| 每请求平均生成速度 | 输出 Token 数 / 总耗时(tokens/s per request) | 单用户体验与吞吐的平衡 | 吞吐提升往往伴随单请求速度下降 |
常见误区:只看“吞吐量”而忽略 TTFT 与 ITL。当 batch size 过大时,虽然总吞吐上升,但每个请求的 ITL 可能从 20ms 恶化到 200ms,导致用户明显感觉“卡顿”。生产环境必须同时设定吞吐目标与延迟上限(SLO)。
2.4 案例:一个 8 请求并发场景的调度快照
假设 GPU 显存可容纳 4 个物理块,每个块可存 16 个 Token 的 KV Cache。现有 8 个请求(Req A~H)并发到达,它们的提示词长度与输出长度各不相同。
在传统静态批处理中,系统会等待所有 8 个请求完成 Prefill 后再统一 decode,导致显存瞬间溢出或大量空闲。而 vLLM 的调度器会这样运作:
- 第 1 步:选择 4 个请求(A~D)进行 Prefill,占用全部 4 个物理块。其余 4 个请求(E~H)在队列中等待。
- 第 2 步:A~D 各自生成 1 个 Token。若 Req A 的提示词较短,其 KV Cache 占用 1 块;Req B 提示词较长,占用 2 块。此时若还有空闲块,调度器将 Req E 加入批次进行 Prefill。
- 第 3 步:若 Req A 已生成完毕(达到 max_tokens),调度器立即释放其物理块,并让队列中的 Req F 进入。整个过程 GPU 始终在处理有效计算,没有等待空闲。
这种动态调度使得 GPU 利用率大幅提升。实测数据显示,在相同硬件与请求分布下,vLLM 的吞吐量可比传统静态批处理提升 2~4 倍,且显存占用降低约 60%(得益于 PagedAttention 消除了内部碎片)。
2.5 误区复盘:性能指标背后的陷阱
在后续调优前,先厘清几个容易误判的指标关系:
复盘清单
- “吞吐高”不等于“效率高”:若通过无限增大 batch size 提升吞吐,可能导致显存溢出或 ITL 急剧恶化。需结合 TTFT 与 ITL 的 SLO 综合评估。
- “KV Cache 利用率高”不等于“无浪费”:利用率高可能意味着请求长度分布均匀,但也可能因块大小设置过大导致内部碎片(如 16-token 块只用了 3 个 token)。需结合平均块占用率分析。
- “Prefill 快”不代表“端到端快”:Prefill 是计算密集型,GPU 利用率高;但 decode 是访存密集型,往往因显存带宽不足而成为瓶颈。优化 Prefill 的算子(如 FlashAttention)对整体吞吐提升有限,除非 Prefill 占比极大。
- “并发数”不等于“吞吐”:增加并发请求数会提升吞吐,但超过某个临界点后,调度开销与显存竞争会导致吞吐下降。这个临界点需要通过压测寻找,而非盲目调大。