3. vLLM基础:核心概念与基本用法
3.1 为什么传统推理服务难以支撑高并发
在深入 vLLM 之前,我们先理解传统 LLM 推理服务的瓶颈。大多数推理框架采用“静态批处理”(Static Batching)方式:请求到达后,要么等待当前批次全部生成完毕,要么单独占用 GPU 资源。这种方式存在两个致命问题:显存碎片化和计算等待。每个请求的 KV Cache(键值缓存)在显存中按最大可能长度预分配,导致大量显存被闲置;同时,批次内所有序列必须同步完成生成,短请求被迫等待长请求。
vLLM 的核心目标就是解决这两个问题,其实现依赖两项关键技术:PagedAttention 和 Continuous Batching。
3.2 PagedAttention:显存管理的“虚拟内存”方案
PagedAttention 借鉴操作系统中的虚拟内存分页思想。传统方案为每个序列分配连续的显存块,而 PagedAttention 将 KV Cache 划分为固定大小的“块”(Block,通常为 16 或 32 个 token 的 KV 数据)。每个序列的 KV Cache 可以存储在多个不连续的物理块中,通过一张块表(Block Table)记录逻辑块到物理块的映射。
- 显存利用率接近 100%:仅按实际使用量分配块,消除内部碎片和预留浪费。
- 共享前缀:多个序列共享相同系统提示词或上下文时,可共享同一物理块,大幅降低显存占用。
- 灵活增长:生成新 token 时动态分配新块,无需预先为最大长度预留空间。
下图展示了 PagedAttention 的块表映射机制,以及两个序列共享前缀块的情形:
图中可见,序列 A 的逻辑块 0 和序列 B 的逻辑块 0 都映射到物理块 P0,实现了前缀共享;而逻辑块 1 分别映射到 P2 和 P3,互不干扰。这种机制使得 vLLM 在长上下文场景下显存占用比传统方案降低 50%~80%。
3.3 Continuous Batching:动态调度与请求级抢占
Continuous Batching(连续批处理)打破了“批次同步完成”的限制。调度器以迭代级别(Iteration-level)进行调度:每完成一个 token 的生成,就检查是否有新请求可以加入、是否有请求已完成。GPU 不再等待整个批次结束,而是持续处理不同进度的序列。
具体流程如下:
- 初始批次包含 3 个请求,各自处于不同生成阶段。
- 每步迭代后,请求 A 提前生成完毕(遇到 EOS 或达到 max_tokens),立即释放其占用的 KV Cache 块。
- 调度器将等待队列中的请求 D 插入当前批次,复用刚释放的显存块。
- 批次内剩余请求继续生成,新请求从 prefill 阶段开始。
3.4 vLLM 基本用法:从启动到调用
vLLM 提供两种主要使用方式:离线批处理(Python API)和在线服务(OpenAI 兼容服务器)。
3.4.1 离线批处理
from vllm import LLM, SamplingParams
# 初始化模型,自动启用 PagedAttention 和 Continuous Batching
llm = LLM(model="Qwen/Qwen2.5-7B-Instruct", gpu_memory_utilization=0.85)
# 定义采样参数
sampling_params = SamplingParams(
temperature=0.7,
top_p=0.9,
max_tokens=512,
stop=["</s>"]
)
# 批量推理
prompts = ["解释什么是量子纠缠", "写一首关于秋天的诗", "总结这篇文章的要点"]
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
print(output.prompt, "→", output.outputs[0].text)
关键参数说明:
| 参数 | 作用 | 推荐值 |
|---|---|---|
| gpu_memory_utilization | 控制用于 KV Cache 的显存比例 | 0.80~0.90 |
| max_num_seqs | 单批次最大序列数 | 256~1024 |
| max_model_len | 模型最大上下文长度 | 与模型配置一致 |
| enable_prefix_caching | 启用前缀缓存,加速重复前缀请求 | True |
3.4.2 在线服务
# 启动 OpenAI 兼容服务器
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-7B-Instruct \
--port 8000 \
--gpu-memory-utilization 0.85 \
--max-num-seqs 512
# 客户端调用(兼容 OpenAI SDK)
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen2.5-7B-Instruct",
"messages": [{"role": "user", "content": "你好"}],
"max_tokens": 128
}'
3.5 案例:多模型混合部署的批处理效果
假设我们在一台 8×A100(80GB)服务器上部署 3 个模型:Qwen2.5-7B、Llama-3-8B、Mistral-7B。使用 vLLM 分别启动 3 个服务实例,每个实例分配 2 张 GPU。通过 Nginx 做负载均衡,将不同业务请求路由到对应模型。
实测数据(请求长度 200~2000 token 混合):
- 传统静态批处理:GPU 利用率约 35%,平均吞吐 1200 token/s。
- vLLM Continuous Batching:GPU 利用率提升至 78%,平均吞吐 4200 token/s。
- 启用前缀缓存后,系统提示词相同的请求延迟降低 60%。
3.6 常见误区与复盘
实际上,即使短文本(如 50 token),PagedAttention 的块分配机制也能减少显存浪费,只是收益不如长文本明显。但 Continuous Batching 对短请求的吞吐提升依然显著。
增大批次大小会提高吞吐,但也会增加显存压力。当 KV Cache 不足时,vLLM 会触发“抢占”(Preemption),将部分序列的 KV Cache 换出到 CPU,反而增加延迟。建议根据实际显存余量逐步调整。
在多轮对话或 RAG 场景中,大量请求共享相同的系统提示词或检索上下文。不开启 enable_prefix_caching 会浪费显存和计算资源。开启后,共享前缀的 KV Cache 只需计算一次。