vLLM 原理:PagedAttention 和 Continuous Batching
vLLM 是目前最流行的大模型推理框架,速度快、吞吐高。
核心技术两个:PagedAttention 和 Continuous Batching。这篇讲清楚它们的原理。
vLLM 是什么
vLLM 是加州大学伯克利分校开源的大模型推理引擎。
主打:高吞吐、低显存浪费。
GitHub:https://github.com/vllm-project/vllm
为什么快
传统推理框架的问题:
- KV Cache 预分配,显存浪费严重
- 静态 Batching,GPU 利用率低
vLLM 解决了这两个问题。
PagedAttention
传统 KV Cache 的问题
传统做法:为每个请求预分配固定大小的 KV Cache。
请求1:预分配 4096 tokens 的空间
实际只用了 500 tokens
浪费率:88%
更糟的是,不同请求的 KV Cache 是连续分配的:
显存布局:
[请求1: 4096][请求2: 4096][请求3: 4096]...
如果请求2结束了:
[请求1: 4096][空洞: 4096][请求3: 4096]...
产生碎片,新请求可能因为找不到连续空间而无法分配。
PagedAttention 的思路
借鉴操作系统的虚拟内存:把 KV Cache 分成固定大小的「页」(block)。
每页存 16 个 token 的 KV
请求1 需要 500 tokens → 分配 32 页
请求2 需要 1000 tokens → 分配 63 页
页可以不连续
工作原理
1. 页表管理
每个请求有一个页表,记录它的 KV Cache 在哪些页上:
请求1 的页表:[页3, 页7, 页12, 页15, ...]
请求2 的页表:[页1, 页5, 页8, 页20, ...]
2. 按需分配
生成 token 时,页不够就分配新页:
请求1 当前 500 tokens,用了 32 页
生成第 501 个 token,还在第 32 页里
生成第 513 个 token(新页),分配第 33 页
3. 及时释放
请求结束,页立即归还:
请求2 结束 → 释放 [页1, 页5, 页8, 页20, ...]
这些页可以给新请求用
优势
1. 几乎零浪费
只分配实际需要的页,不预留最大长度。
传统:每个请求分配 4096 tokens 空间
PagedAttention:用多少分多少
实测显存利用率从 ~50% 提升到 ~95%
2. 无碎片
页是固定大小,用完就还,不产生碎片。
3. 支持共享
相同前缀的请求可以共享 KV Cache:
请求1:「你好,请介绍一下北京」
请求2:「你好,请介绍一下上海」
「你好,请介绍一下」的 KV Cache 可以共享
Beam Search、Parallel Sampling 等场景效率大增。
Continuous Batching
传统 Batching 的问题
静态 Batching:凑够一批请求一起处理。
等待凑够 batch_size=8 的请求
开始处理
所有请求都完成后,处理下一批
问题:
- 等待时间长(要凑够一批)
- 短请求等长请求(一批里最长的请求完成才能开始下一批)
请求1:生成 10 个 token,很快完成
请求2:生成 500 个 token
请求3:生成 20 个 token
静态 Batching:
请求1 等请求2,要等很久
请求3 也等请求2
GPU 在处理请求2 时,请求1 和 3 的位置空着
Continuous Batching
动态调度:请求随到随处理,完成随时离开。
Iteration 1:处理 [请求1, 请求2, 请求3]
请求1 完成,离开
Iteration 2:处理 [请求2, 请求3, 请求4(新来的)]
请求3 完成,离开
Iteration 3:处理 [请求2, 请求4, 请求5(新来的)]
...
每次迭代:
- 检查有没有请求完成,释放位置
- 检查有没有新请求,加入 batch
- 执行一步推理
优势
1. 延迟更低
新请求不用等凑批,来了就能处理。
2. 吞吐更高
GPU 始终在满负荷工作,不浪费位置。
静态 Batching:完成率波动大
Continuous Batching:稳定的高吞吐
3. 短请求不等长请求
10 token 的请求生成完就离开,不用等 500 token 的请求。
vLLM 的调度
PagedAttention 解决显存问题,Continuous Batching 解决调度问题。vLLM 把两者结合起来。
调度流程
while True:
# 1. 检查完成的请求
for req in running_requests:
if req.finished():
release_pages(req)
running_requests.remove(req)
# 2. 检查新请求
while has_free_pages() and waiting_requests:
req = waiting_requests.pop()
allocate_pages(req)
running_requests.add(req)
# 3. 执行一步推理
outputs = model.forward(running_requests)
# 4. 更新 KV Cache
for req, output in zip(running_requests, outputs):
req.append_token(output)
Preemption(抢占)
显存不够时,可以把一些请求「挂起」:
显存快满了
请求3 优先级低,暂时挂起
释放请求3 的页
给更紧急的请求用
请求3 稍后恢复(重新计算或从 swap 恢复)
vLLM 支持两种抢占模式:
- Recompute:重新计算 KV Cache
- Swap:把 KV Cache 换到 CPU
使用 vLLM
安装
pip install vllm
离线推理
from vllm import LLM, SamplingParams
llm = LLM(model="meta-llama/Llama-2-7b-hf")
prompts = [
"Hello, my name is",
"The capital of France is",
"The future of AI is",
]
sampling_params = SamplingParams(
temperature=0.8,
top_p=0.95,
max_tokens=256
)
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
print(output.outputs[0].text)
在线服务
# 启动服务
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-2-7b-hf \
--host 0.0.0.0 \
--port 8000
# 调用(兼容 OpenAI API)
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Llama-2-7b-hf",
"prompt": "Hello, my name is",
"max_tokens": 100
}'
重要参数
LLM(
model="...",
# 显存相关
gpu_memory_utilization=0.9, # GPU 显存利用率
max_model_len=4096, # 最大上下文长度
# 并行相关
tensor_parallel_size=2, # 张量并行(多卡)
# 量化
quantization="awq", # 量化方法
# KV Cache
block_size=16, # 页大小(tokens)
)
性能对比
vs HuggingFace Transformers
| 指标 | HF Transformers | vLLM |
|---|---|---|
| 吞吐(tokens/s) | 基准 | 2-4x |
| 显存利用率 | ~50% | ~95% |
| 延迟 | 较高 | 较低 |
实测数据
LLaMA-7B,单卡 A100:
| 并发数 | HF (tokens/s) | vLLM (tokens/s) |
|---|---|---|
| 1 | 30 | 35 |
| 8 | 100 | 250 |
| 32 | 150 | 800 |
| 128 | OOM | 1500 |
并发越高,vLLM 优势越明显。
局限性
1. 首 token 延迟
PagedAttention 有一些额外开销,TTFT 可能略高于简单实现。
对延迟极其敏感的场景要注意。
2. 显存开销
页表管理本身需要一些显存。
小模型或单请求场景,优势不明显。
3. 模型支持
不是所有模型都支持,需要适配。
主流模型(LLaMA、Mistral、Qwen 等)都支持了。
其他优化
vLLM 还有一些其他优化:
FlashAttention
优化 Attention 计算的访存模式,减少显存访问。
vLLM 集成了 FlashAttention。
Speculative Decoding
用小模型快速生成草稿,大模型验证。
一次验证多个 token,减少大模型调用次数。
Prefix Caching
缓存常用 prefix 的 KV Cache,避免重复计算。
比如系统 prompt 被很多请求共用,可以缓存起来。
小结
vLLM 的核心技术:
PagedAttention:
- 把 KV Cache 分页管理
- 按需分配,无碎片
- 支持共享
- 显存利用率从 50% 提升到 95%
Continuous Batching:
- 动态调度请求
- 请求随到随处理,完成随走
- 短请求不等长请求
- GPU 利用率大幅提升
效果:
- 吞吐提升 2-4 倍
- 支持更高并发
- 延迟更稳定
推理服务首选 vLLM。
下一篇对比主流推理框架:vLLM vs TensorRT-LLM vs SGLang。