vLLM 高性能推理部署指南 / 01 - vLLM 概述与技术原理
01 - vLLM 概述与技术原理
理解 vLLM 的设计哲学与核心技术,为后续实践打下坚实基础。
1.1 什么是 vLLM?
vLLM(发音 “vee-LLM”)是 UC Berkeley RISE Lab 开源的高吞吐量大语言模型推理和服务引擎。项目始于 2023 年,凭借 PagedAttention 技术一举成名,现已成为 LLM 推理领域最广泛使用的开源引擎之一。
项目定位
┌─────────────────────────────────────────────────────┐
│ LLM 部署技术栈 │
├─────────────┬───────────────┬───────────────────────┤
│ 模型层 │ 推理引擎层 │ 服务层 │
│ │ │ │
│ HuggingFace│ vLLM ◀──── │── OpenAI API │
│ ModelScope │ TGI │ gRPC │
│ 自训练模型 │ Ollama │ REST API │
│ │ TensorRT-LLM│ 负载均衡 │
└─────────────┴───────────────┴───────────────────────┘
vLLM 专注于推理引擎层,提供:
- 极致的推理吞吐量
- 与 OpenAI API 完全兼容的服务接口
- 灵活的模型加载和适配器管理
- 生产级别的稳定性和可观测性
关键数据
| 指标 | 数值 |
|---|---|
| GitHub Stars | 50,000+(截至 2025 年) |
| 吞吐量提升 | 相比 HuggingFace Transformers 2-24x |
| 内存效率 | KV Cache 浪费 < 4% |
| 支持模型数 | 100+ 种主流 LLM |
| 活跃贡献者 | 1000+ |
1.2 LLM 推理的核心挑战
在理解 vLLM 之前,需要先了解 LLM 推理面临的核心挑战。
1.2.1 KV Cache 内存瓶颈
Transformer 模型在自回归生成(autoregressive generation)过程中,每个 token 的注意力计算需要访问之前所有 token 的 Key 和 Value 向量。为避免重复计算,这些向量被缓存在 KV Cache 中。
生成序列: [token_1] [token_2] [token_3] [token_4] ...
↓ ↓ ↓ ↓
KV Cache: [K1,V1] [K2,V2] [K3,V3] [K4,V4] ...
─────────────────────────────────────→
不断增长
问题:KV Cache 的内存占用随序列长度线性增长,对于长上下文模型,KV Cache 可能消耗 数倍于模型权重 的 GPU 内存。
以 LLaMA-2 70B 为例:
| 参数 | 值 |
|---|---|
| 模型参数量 | 70B |
| 模型权重(FP16) | ~140 GB |
| 单序列 KV Cache(4096 tokens) | ~2.5 GB |
| 单序列 KV Cache(32K tokens) | ~20 GB |
1.2.2 传统内存管理的低效
传统方法(如 HuggingFace Transformers)为每个请求预分配连续的、固定大小的内存空间来存放 KV Cache:
传统方式(固定分配):
GPU 内存:
┌──────────┬──────────┬──────────┬──────────┐
│ 序列1 │ 序列2 │ 序列3 │ 空闲 │
│ ████░░░░ │ ██░░░░░░ │ ██████░░ │ ░░░░░░░░ │
│ 实际用40% │ 实际用25% │ 实际用75% │ │
└──────────┴──────────┴──────────┴──────────┘
████ = 实际使用的 KV Cache
░░░░ = 预分配但未使用的空间(内存碎片/浪费)
这种方式导致两个严重问题:
- 内部碎片(Internal Fragmentation):预分配的空间大部分被浪费
- 外部碎片(External Fragmentation):内存中出现无法使用的小空洞
实测表明,传统方式下 KV Cache 的内存浪费率高达 60%-80%。
1.3 PagedAttention:vLLM 的核心创新
1.3.1 核心思想
PagedAttention 借鉴了操作系统中**虚拟内存分页(Virtual Memory Paging)**的思想:
| 操作系统概念 | PagedAttention 对应 |
|---|---|
| 虚拟内存页(Page) | KV Cache 块(Block) |
| 物理内存帧(Frame) | GPU 显存块 |
| 页表(Page Table) | 块表(Block Table) |
| 按需分配 | 按需分配 KV Cache 块 |
| 页面置换 | 块驱逐(Block Eviction) |
1.3.2 工作原理
PagedAttention(分页分配):
逻辑视图(对请求透明):
序列1: [Block0][Block1]
序列2: [Block0]
序列3: [Block0][Block1][Block2]
物理 GPU 内存(非连续分配):
┌────────┬────────┬────────┬────────┬────────┬────────┐
│ 物理块0 │ 物理块1 │ 物理块2 │ 物理块3 │ 物理块4 │ 物理块5 │
│ Seq1-B0│ Seq3-B0│ Seq1-B1│ Seq2-B0│ Seq3-B1│ Seq3-B2│
└────────┴────────┴────────┴────────┴────────┴────────┘
↑ 块表维护逻辑块到物理块的映射 ↑
核心优势:
- 按需分配:只为实际生成的 token 分配内存,无需预分配最大长度
- 无碎片化:固定大小的块消除了外部碎片
- 高效共享:多个请求可以共享相同前缀的 KV Cache(如系统提示词)
1.3.3 内存效率对比
| 管理方式 | KV Cache 内存浪费率 | 支持的并发请求数 |
|---|---|---|
| 固定分配(传统) | 60%-80% | 基准 |
| PagedAttention | < 4% | 2-4x 基准 |
1.3.4 Copy-on-Write 机制
PagedAttention 还实现了 **Copy-on-Write(写时复制)**机制,用于高效的 beam search 和并行采样:
Beam Search 示例(num_beams=3):
Step 1: 共享前缀 KV Cache
┌─────────────────────┐
│ 前缀 Block (共享) │ ← 引用计数 = 3
└─────────────────────┘
↑ ↑ ↑
Beam1 Beam2 Beam3
Step 2: 分叉后各自写入新 block
┌──────────────┐
│ 前缀 Block │ ← 引用计数 = 3(仍然共享)
├──────┬───────┤
│ B1新 │ B2新 │ ← 各自独立
└──────┴───────┘
1.4 vLLM 核心特性详解
1.4.1 连续批处理(Continuous Batching)
传统静态批处理(Static Batching)必须等待整个批次中最长的序列完成才能处理下一批:
静态批处理:
时间 →
请求1: ████████████████
请求2: ██████████
请求3: ████████████████████
↑ 必须全部完成才能处理下一批
GPU: [─── 批次1 ───][ 等待 ][─── 批次2 ───]
vLLM 的连续批处理在每个生成步骤后动态插入新请求:
连续批处理:
时间 →
请求1: ████████████████
请求2: ██████████
请求3: ████████████████████ ← 请求2完成后立即插入
请求4: ██████████
GPU: [──── 无空闲,持续工作 ────]
效果:GPU 利用率从 50%-70% 提升至 90%+。
1.4.2 丰富的模型支持
vLLM 支持主流的 LLM 架构:
| 类别 | 支持的模型 |
|---|---|
| LLaMA 系列 | LLaMA, LLaMA-2, LLaMA-3, Code LLaMA |
| Mistral 系列 | Mistral, Mixtral (MoE) |
| Qwen 系列 | Qwen, Qwen-2, Qwen-2.5 |
| ChatGLM | ChatGLM-2, ChatGLM-3, GLM-4 |
| DeepSeek | DeepSeek, DeepSeek-V2, DeepSeek-Coder |
| Yi | Yi, Yi-1.5 |
| Phi | Phi-2, Phi-3 |
| Gemma | Gemma, Gemma-2 |
| 多模态 | LLaVA, Qwen-VL, InternVL |
1.4.3 量化推理
vLLM 支持多种量化方法,可以在更少的 GPU 上运行更大的模型:
| 量化方法 | 精度损失 | 速度影响 | 适用场景 |
|---|---|---|---|
| AWQ | 低 | 快 1.5-2x | 推荐首选 |
| GPTQ | 低 | 快 1.3-1.8x | 兼容性好 |
| FP8 | 极低 | 快 1.5x | H100/H200 专属 |
| INT8 (LLM.int8()) | 中 | 快 1.2x | 通用 GPU |
| BitsAndBytes | 中 | 有限 | 快速实验 |
1.4.4 LoRA 动态适配
vLLM 支持在不重启服务的情况下动态加载和切换 LoRA 适配器:
┌─── LoRA 适配器 A(医疗) ← 请求1使用
基础模型 ────────────┤
(保持不变) ├─── LoRA 适配器 B(法律) ← 请求2使用
│
└─── LoRA 适配器 C(金融) ← 请求3使用
应用场景:
- 多租户服务:每个租户使用不同的 LoRA 适配器
- A/B 测试:同时运行多个微调版本
- 多语言支持:不同语言的 LoRA 适配器
1.4.5 前缀缓存(Automatic Prefix Caching)
当多个请求共享相同的系统提示词时,vLLM 可以自动复用 KV Cache:
请求1: [系统提示词] + [用户问题 A]
请求2: [系统提示词] + [用户问题 B]
请求3: [系统提示词] + [用户问题 C]
传统方式:系统提示词的 KV Cache 计算 3 次
APC 方式:系统提示词的 KV Cache 计算 1 次,复用 2 次
1.5 主流 LLM 推理引擎对比
1.5.1 综合对比表
| 特性 | vLLM | Ollama | TGI | TensorRT-LLM | llama.cpp |
|---|---|---|---|---|---|
| 定位 | 高吞吐服务 | 本地体验 | 生产服务 | 极致性能 | 轻量推理 |
| PagedAttention | ✅ 原创 | ❌ | ✅ 引入 | ✅ | ❌ |
| 连续批处理 | ✅ | ❌ | ✅ | ✅ | ❌ |
| 张量并行 | ✅ | ❌ | ✅ | ✅ | 有限 |
| 流水线并行 | ✅ | ❌ | ❌ | ✅ | ❌ |
| 量化支持 | 多种 | GGUF | 有限 | 多种 | GGUF |
| LoRA 热加载 | ✅ | ❌ | ✅ | ❌ | 有限 |
| OpenAI 兼容 API | ✅ | ✅ | ❌ | 需额外 | ✅ |
| 流式输出 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 多模态 | ✅ | 有限 | ✅ | ✅ | 有限 |
| CUDA 依赖 | 必需 | 可选 | 必需 | 必需 | 可选 |
| 部署复杂度 | 中 | 低 | 中 | 高 | 低 |
| 社区活跃度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
1.5.2 vLLM vs Ollama
| 维度 | vLLM | Ollama |
|---|---|---|
| 目标用户 | AI 工程师、生产环境 | 普通开发者、本地体验 |
| 性能 | 高吞吐、低延迟 | 吞吐量较低 |
| 资源需求 | 需要 NVIDIA GPU | 支持 CPU/Apple Silicon |
| 模型管理 | 从 HuggingFace 加载 | 自有模型库(类 Docker Hub) |
| 扩展性 | 多卡并行、分布式 | 单机为主 |
| API | OpenAI 完全兼容 | OpenAI 基础兼容 |
| 适用场景 | 生产服务、高并发 | 本地开发、Demo 演示 |
选择建议:
- 快速体验 LLM → Ollama
- 生产部署、高并发 → vLLM
1.5.3 vLLM vs TGI(Text Generation Inference)
| 维度 | vLLM | TGI |
|---|---|---|
| 开发方 | UC Berkeley + 社区 | Hugging Face |
| 语言 | Python (+ CUDA) | Rust (+ Python) |
| 核心优势 | PagedAttention、灵活性 | 生态集成、稳定性 |
| HuggingFace 集成 | 良好 | 原生 |
| LoRA 支持 | 动态多 LoRA | 单 LoRA |
| 流水线并行 | ✅ | ❌ |
| 社区治理 | 开放社区 | HuggingFace 主导 |
| 许可证 | Apache 2.0 | Apache 2.0(HF 限制条款) |
选择建议:
- 深度 HuggingFace 生态集成 → TGI
- 灵活部署、多 LoRA、前沿特性 → vLLM
1.5.4 vLLM vs TensorRT-LLM
| 维度 | vLLM | TensorRT-LLM |
|---|---|---|
| 开发方 | 社区 | NVIDIA |
| 部署复杂度 | 中等 | 高(需模型编译) |
| 极致性能 | 优秀 | 极致(10-20% 优势) |
| 灵活性 | 高 | 较低(需重新编译) |
| 模型支持速度 | 快(新模型快速适配) | 较慢(需 NVIDIA 更新) |
| 硬件绑定 | 通用 NVIDIA GPU | 仅 NVIDIA GPU |
选择建议:
- 追求极致性能、稳定模型 → TensorRT-LLM
- 快速迭代、灵活部署 → vLLM
1.6 vLLM 生态系统
1.6.1 集成生态
┌──────────────────┐
│ vLLM Engine │
└────────┬─────────┘
┌──────────────┬───┴───┬──────────────┐
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐
│ LangChain│ │ LlamaIndex│ │ FastAPI │ │ K8s │
│ │ │ │ │ │ │ Helm │
└──────────┘ └──────────┘ └─────────┘ └─────────┘
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐
│ Ray Serve│ │ OpenAI │ │Dify │ │ SkyPilot│
│ │ │ SDK │ │ │ │ │
└──────────┘ └──────────┘ └─────────┘ └─────────┘
1.6.2 版本演进
| 版本 | 发布时间 | 重要特性 |
|---|---|---|
| v0.1 | 2023.06 | PagedAttention 首次发布 |
| v0.2 | 2023.09 | 连续批处理、张量并行 |
| v0.3 | 2024.01 | LoRA 热加载、前缀缓存 |
| v0.4 | 2024.03 | FP8 量化、Speculative Decoding |
| v0.5 | 2024.06 | 多模态支持、流水线并行 |
| v0.6 | 2024.09 | 性能优化、更多模型支持 |
| v0.7+ | 2025+ | 持续优化、新特性迭代 |
1.7 业务场景
场景一:企业级 AI 助手服务
用户请求 → 负载均衡 → vLLM 集群(多实例)→ 响应
├── 实例1: 4x A100
├── 实例2: 4x A100
└── 实例3: 4x A100
- 需求:低延迟、高并发、多模型
- vLLM 方案:张量并行 + 连续批处理 + LoRA 多租户
场景二:多模型推理平台
┌── vLLM 实例 1: Qwen-72B(通用对话)
请求路由 ─────┤
├── vLLM 实例 2: CodeLLaMA-34B(代码生成)
│
└── vLLM 实例 3: 多 LoRA(医疗/法律/金融)
场景三:批量离线处理
# 批量处理数百万条数据
llm = LLM(model="Qwen/Qwen2.5-7B-Instruct")
prompts = load_large_dataset("prompts.jsonl") # 100万条
outputs = llm.generate(prompts) # 高吞吐批量推理
1.8 注意事项
硬件要求:vLLM 需要 NVIDIA GPU,不支持 AMD GPU(截至 v0.6.x)和纯 CPU 推理。
CUDA 版本:推荐 CUDA 12.1+,部分特性(如 FP8)需要 CUDA 12.4+。
模型格式:vLLM 主要支持 HuggingFace 格式的模型权重,GGUF 格式需通过 llama.cpp 转换。
显存规划:除了模型权重,还需为 KV Cache 预留充足显存。建议预留 20%-30% 的 GPU 显存用于 KV Cache。
1.9 扩展阅读
- vLLM 官方文档
- vLLM GitHub 仓库
- PagedAttention 论文
- Efficient Memory Management for LLM Serving with PagedAttention (SOSP 2023)
- OS Concepts Applied to LLM Serving - vLLM Blog
- HuggingFace TGI 仓库
- Ollama 官网
- TensorRT-LLM 文档
下一章:02 - 安装与环境配置 — 从零搭建 vLLM 运行环境。