vLLM推理加速深度解读:PagedAttention如何提升10x吞吐量
1. 引言
在大语言模型(Large Language Models, LLMs)快速发展的今天,推理效率已成为制约模型落地的关键瓶颈。GPT-4、LLaMA、Claude等模型虽然能力强大,但推理成本高昂、延迟较长,严重限制了商业化应用。统计显示,部署一个ChatGPT级别的服务,推理成本占据总运营成本的70%以上。
vLLM(Very Fast LLM Inference)是UC Berkeley提出的高性能LLM推理引擎,通过革命性的PagedAttention技术,将LLM推理吞吐量提升了2-24倍,同时大幅降低内存占用。这项技术已被广泛应用于OpenAI API、Anthropic Claude、阿里通义千问等主流AI服务。
vLLM的核心创新在于:将操作系统的虚拟内存管理思想应用到LLM推理的KV Cache管理中,解决了传统推理系统中内存碎片化和预分配浪费的问题。本文将深入剖析vLLM的技术原理、实现细节及最新进展。
2. 核心原理
2.1 LLM推理的内存瓶颈
在理解vLLM之前,我们需要先理解LLM推理过程中的关键挑战:KV Cache。
在Transformer架构中,自注意力机制计算公式为:
其中:
(Query):当前token的查询向量
(Key):所有历史token的键向量
(Value):所有历史token的值向量
:键向量的维度
在自回归生成过程中,每生成一个新token,都需要访问之前所有token的Key和Value向量。为避免重复计算,系统会将历史的K、V向量缓存在GPU显存中,这就是KV Cache。
对于一个LLaMA-13B模型(40层、40个注意力头、每头维度128),单个token的KV Cache大小为:
生成1024个token需要约800MB显存!对于批量推理(batch size=32),KV Cache占用可达25GB,远超模型参数本身(13B参数约26GB)。
2.2 传统推理系统的问题
问题1:内存预分配浪费
传统系统(如HuggingFace Transformers)采用静态预分配策略:为每个请求预留最大序列长度(如2048 tokens)的KV Cache空间。但实际生成长度往往远小于最大长度(平均约200-500 tokens),导致60-80%的显存被浪费。
问题2:内存碎片化
不同请求的生成长度各异,动态分配会产生大量内存碎片。当碎片累积到一定程度,即使总空闲显存充足,也无法分配连续的大块内存,导致Out-of-Memory错误。
问题3:动态Batching困难
传统系统难以高效实现Continuous Batching(连续批处理):当一个请求完成时,无法立即释放显存并加入新请求,导致GPU利用率低下。
2.3 PagedAttention:虚拟内存启发
vLLM的核心创新PagedAttention受操作系统虚拟内存管理启发:
虚拟内存的核心思想:
将物理内存划分为固定大小的页(Page)
程序使用虚拟地址,由页表映射到物理页
支持非连续的物理内存分配
按需分配,减少浪费
PagedAttention的设计:

KV Cache分页:将KV Cache划分为固定大小的Block(如16或32个token)
-
逻辑地址与物理地址分离:
逻辑地址:请求视角的连续KV Cache地址
物理地址:GPU显存中的实际存储位置
通过Block Table(类似页表)建立映射
按需分配:请求生成时动态分配Block,避免预分配浪费
内存共享:不同请求可共享相同的Prompt Block(如系统提示词),节省显存
数学上,PagedAttention的注意力计算修改为:
其中 和
不再是连续存储,而是通过Block Table索引:
:Block大小(token数量)
:逻辑Block到物理Block的映射表
:物理显存中的KV Cache
2.4 架构设计
vLLM采用分离式架构:
Scheduler(调度器):管理请求队列,决定哪些请求参与本次推理
Block Manager(块管理器):负责Block的分配、回收和共享
Worker(工作进程):执行实际的推理计算
KV Cache Manager:维护Block Table和物理显存

整体流程:
用户请求到达 → Scheduler加入队列
Scheduler根据可用Block决定本轮batch
Block Manager分配Block并更新Block Table
Worker执行PagedAttention计算
生成完成 → 回收Block → 调度新请求
3. 技术演进
3.1 早期LLM推理系统
FasterTransformer (NVIDIA, 2021)
首次针对LLM推理优化
采用静态内存预分配
支持Tensor并行和Pipeline并行
问题:内存利用率低(<30%)
Orca (Microsoft, 2022)
提出Iteration-level Batching
允许不同请求有不同的生成长度
仍存在内存碎片化问题
3.2 vLLM的诞生
vLLM (UC Berkeley, 2023.6) [Kwon et al., SOSP 2023]
论文:Efficient Memory Management for Large Language Model Serving with PagedAttention
核心贡献:
首次提出PagedAttention算法
实现KV Cache的非连续存储
Block级别的内存管理
实验证明:吞吐量提升2-24倍
实验数据(LLaMA-13B, A100 GPU):
内存利用率:从35%提升至90%
吞吐量:2297 tokens/s(相比HF的221 tokens/s提升10.4倍)
支持的并发请求数:从5个提升至50个
3.3 后续优化
vLLM v0.2 (2023.10)
支持Prefix Caching:共享相同Prompt的KV Cache
支持Chunked Prefill:将长Prompt分块处理
引入Speculative Decoding:推测解码加速
vLLM v0.3 (2024.2)
支持Multi-LoRA:同时服务多个LoRA适配器
引入Automatic Prefix Caching (APC)
支持FP8量化
4. 实现细节
4.1 Block管理器实现
Block数据结构:
class Block:
def __init__(self, block_id: int, block_size: int):
self.block_id = block_id # 物理Block ID
self.ref_count = 0 # 引用计数
self.tokens = [] # 存储的token IDs
self.is_full = False # 是否已满
class BlockTable:
def __init__(self):
self.logical_to_physical = {} # 逻辑块 -> 物理块映射
self.physical_blocks = [] # 所有物理块池
Block分配算法:
def allocate_block(request_id: int) -> Block:
"""为请求分配一个新Block"""
# 1. 从空闲池中获取Block
if free_blocks:
block = free_blocks.pop()
else:
# 2. 显存不足,执行Eviction
block = evict_least_recent_block()
# 3. 更新Block Table
logical_id = len(block_tables[request_id])
block_tables[request_id][logical_id] = block.block_id
# 4. 增加引用计数
block.ref_count += 1
return block
def share_block(src_request_id: int, dst_request_id: int,
logical_block_id: int):
"""共享Block(用于Prefix Caching)"""
physical_id = block_tables[src_request_id][logical_block_id]
block_tables[dst_request_id].append(physical_id)
physical_blocks[physical_id].ref_count += 1
4.2 PagedAttention CUDA Kernel
核心计算挑战:K、V不再连续存储,需要在CUDA kernel中处理映射。
优化策略:
Block-wise计算:按Block遍历,每个Block内仍是连续的
Shared Memory缓存:将Block Table加载到Shared Memory
Warp-level优化:一个Warp处理一个Query head
简化的CUDA伪代码:
__global__ void paged_attention_kernel(
float* Q, // [num_heads, head_size]
float* K_cache, // [num_blocks, block_size, num_heads, head_size]
float* V_cache, // [num_blocks, block_size, num_heads, head_size]
int* block_table, // [max_blocks]
float* output, // [num_heads, head_size]
int num_blocks,
int block_size
) {
int head_id = blockIdx.x;
int thread_id = threadIdx.x;
// 加载Block Table到Shared Memory
__shared__ int block_table_shared[MAX_BLOCKS];
if (thread_id < num_blocks) {
block_table_shared[thread_id] = block_table[thread_id];
}
__syncthreads();
float local_sum = 0.0;
// 遍历所有Block
for (int block_idx = 0; block_idx < num_blocks; block_idx++) {
int physical_block_id = block_table_shared[block_idx];
// 遍历Block内的token
for (int token_idx = 0; token_idx < block_size; token_idx++) {
// 计算注意力分数
float score = 0.0;
for (int i = thread_id; i < head_size; i += blockDim.x) {
score += Q[head_id * head_size + i] *
K_cache[physical_block_id][token_idx][head_id][i];
}
// Warp reduction求和
score = warp_reduce_sum(score);
// 累加到输出
local_sum += score * V_cache[physical_block_id][token_idx][head_id][thread_id];
}
}
output[head_id * head_size + thread_id] = local_sum;
}
4.3 Continuous Batching实现
vLLM的一大亮点是请求级调度:每次forward后重新调度。
class Scheduler:
def schedule(self) -> Batch:
"""每次调度决定本轮batch"""
selected_requests = []
total_blocks_needed = 0
# 1. 优先调度正在生成的请求(避免饥饿)
for req in running_requests:
blocks_needed = 1 if req.last_block_is_full else 0
if total_blocks_needed + blocks_needed <= free_blocks:
selected_requests.append(req)
total_blocks_needed += blocks_needed
# 2. 尽可能添加等待队列中的请求
for req in waiting_requests:
# 估算Prefill需要的Block数
prompt_blocks = ceil(req.prompt_length / BLOCK_SIZE)
if total_blocks_needed + prompt_blocks <= free_blocks:
selected_requests.append(req)
total_blocks_needed += prompt_blocks
else:
break # 显存不足,停止添加
return Batch(selected_requests)
关键技术点:
Prefill-Decode分离:Prefill(处理Prompt)和Decode(生成token)可在同一batch
动态Batch大小:根据显存实时调整,最大化吞吐
Preemption机制:显存不足时可暂停低优先级请求
4.4 Prefix Caching优化
当多个请求共享相同Prefix(如系统提示词)时,可复用KV Cache。
实现原理:
计算Prefix的哈希值:
hash(token_ids[:prefix_length])维护Prefix Cache Table:
hash -> List[physical_block_ids]新请求到达时,查找匹配的Prefix,直接复用Block(仅增加引用计数)
收益分析:
对于固定系统提示词(如100 tokens),可节省100/2048 ≈ 5%显存
在对话场景中,历史对话可作为Prefix,节省更多
5. 应用场景
5.1 在线服务部署
典型场景:ChatGPT式对话服务
高并发(数千QPS)
不同请求长度差异大(10-2000 tokens)
需要低延迟(<1秒首token)
vLLM优势:
Continuous Batching确保高吞吐
PagedAttention减少显存浪费,支持更多并发
Prefix Caching加速系统提示词处理
实际案例:
Anthropic Claude API:使用vLLM作为推理引擎
阿里通义千问:基于vLLM定制的推理系统
Together.ai:提供vLLM托管服务
5.2 批量离线推理
场景:数据标注、内容生成
需要处理数百万条数据
允许一定延迟
追求最大吞吐量
vLLM配置:
增大Block Size(如64 tokens)减少索引开销
禁用Prefix Caching(离线数据少重复)
最大化Batch Size
5.3 与其他系统对比
| 系统 | 吞吐量 (tokens/s) | 内存利用率 | 支持特性 |
|---|---|---|---|
| HuggingFace Transformers | 221 | 35% | 基础推理 |
| FasterTransformer | 456 | 42% | 张量并行 |
| TensorRT-LLM | 1124 | 58% | 算子融合、INT8 |
| vLLM | 2297 | 90% | PagedAttention、Continuous Batching |
| vLLM + Prefix Caching | 3145 | 95% | 共享Prefix、APC |

(测试条件:LLaMA-13B, A100 40GB, Batch Size = 32)
选型建议:
简单推理、低并发:HuggingFace Transformers
追求极致延迟、单请求:TensorRT-LLM
高并发在线服务:vLLM
对话场景、固定Prompt:vLLM + Prefix Caching
6. 最新研究
6.1 2024年重要进展
SGLang (2024.3) [Zheng et al., arXiv 2024]
扩展vLLM,支持结构化生成(JSON Schema、正则表达式约束)
RadixAttention:基于Radix Tree的更高效Prefix Caching
吞吐量再提升3-5倍
Splitwise (2024.5) [Patel et al., arXiv 2024]
Prefill和Decode分离到不同GPU
Prefill用高显存GPU(A100),Decode用多张低显存GPU(4090)
成本降低40%
DistServe (2024.7) [Liu et al., OSDI 2024]
跨机器的分布式PagedAttention
支持万亿参数模型推理
Block在机器间迁移和共享
6.2 开源项目推荐
-
vLLM官方仓库
支持50+模型(LLaMA、Mistral、Qwen、GLM等)
易用API,兼容OpenAI接口
-
SGLang
适合需要结构化输出的场景
与LangChain、DSPy集成
-
TensorRT-LLM + vLLM
NVIDIA官方支持vLLM backend
结合TensorRT的算子优化和vLLM的内存管理
6.3 未来研究方向
方向1:异构硬件支持
当前vLLM主要针对NVIDIA GPU
AMD GPU(ROCm)、华为昇腾、海光DCU适配
NPU/TPU的PagedAttention实现
方向2:长文本优化
当前Block Size固定(16-32 tokens)
长文本(100K+ tokens)下Block数量爆炸
研究可变Block Size或层级Block结构
方向3:多模态扩展
图像、音频的KV Cache管理
Vision Transformer的PagedAttention
跨模态的Prefix Caching
方向4:端侧推理
手机、IoT设备的内存更紧张
MNN、NCNN集成PagedAttention
Block在DRAM和Flash间调度
7. 总结
vLLM通过PagedAttention技术,将操作系统的虚拟内存管理思想创造性地应用到LLM推理中,解决了KV Cache管理的核心痛点。其核心创新包括:
KV Cache分页存储:打破连续内存限制,消除碎片化
按需分配:避免预分配浪费,内存利用率从35%提升至90%
Continuous Batching:请求级动态调度,吞吐量提升10倍
Prefix Caching:共享相同Prompt,进一步节省显存
vLLM已成为LLM推理的事实标准,被OpenAI、Anthropic、阿里等顶级AI公司采用。对于AI工程师而言,深入理解vLLM的原理不仅有助于优化推理服务,更能启发我们:跨领域的技术迁移往往能带来革命性突破。
学习建议:
阅读vLLM论文(SOSP 2023),理解核心算法
实践:在自己的项目中部署vLLM,对比HuggingFace的性能差异
阅读源码:重点关注
core/block_manager.py和CUDA kernel实现关注最新进展:订阅vLLM GitHub仓库,跟踪SGLang、DistServe等项目
在LLM落地的道路上,推理优化是不可逾越的关键一环。掌握vLLM,就是掌握了LLM工程化的核心竞争力。
参考文献:
Kwon et al., "Efficient Memory Management for Large Language Model Serving with PagedAttention", SOSP 2023
Zheng et al., "SGLang: Efficient Execution of Structured Language Model Programs", arXiv 2024
Patel et al., "Splitwise: Efficient Generative LLM Inference Using Phase Splitting", arXiv 2024
Liu et al., "DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving", OSDI 2024
Yu et al., "Orca: A Distributed Serving System for Transformer-Based Generative Models", OSDI 2022
Vaswani et al., "Attention Is All You Need", NeurIPS 2017