3、vLLM核心机制:PagedAttention原理、显存碎片化问题、KV Cache管理
3.1 从传统显存管理到PagedAttention
在大语言模型推理过程中,KV Cache(键值缓存)是决定吞吐量的核心瓶颈。传统推理框架(如HuggingFace Transformers)采用静态连续显存分配策略:在请求开始前,根据最大序列长度一次性预留完整的KV Cache空间。这种方式存在两个严重问题:
- 内部碎片:实际生成长度远小于最大长度时,预留空间被浪费;
- 外部碎片:不同请求的KV Cache大小不同,频繁分配释放导致显存空洞。
vLLM借鉴操作系统虚拟内存的分页思想,提出了PagedAttention机制。它将KV Cache划分为固定大小的块(Block),每个块可存储固定数量token的键值张量。逻辑上连续的KV Cache在物理显存中可以不连续存放,通过块表(Block Table)维护映射关系。这种设计使显存利用率接近100%,因为只有实际生成的token才会占用物理块。
3.2 KV Cache管理核心机制
PagedAttention的块管理涉及三个关键数据结构:Block Table(块表)、Free Block List(空闲块列表)和Reference Count(引用计数)。每个请求维护一张块表,记录其逻辑块到物理块的映射。调度器在每次解码迭代中执行以下流程:
- 检查:当前请求的最后一个逻辑块是否还有剩余slot;
- 分配:若无剩余slot,从空闲列表中取出一个物理块,追加到块表末尾;
- 写入:将新token的Key和Value张量写入对应slot;
- 释放:请求完成时,遍历其块表,将每个物理块的引用计数减1;若引用计数归零,则归还空闲列表。
vLLM还实现了Copy-on-Write(写时复制)机制用于支持并行采样(beam search)。多个采样序列共享同一前缀的物理块,只有当某个序列需要写入不同内容时才复制该块。这极大减少了多序列生成时的显存开销。
3.3 显存碎片化问题与解决路径
尽管PagedAttention解决了大部分碎片问题,但仍有块内碎片存在:每个物理块固定存储16个token(默认block_size=16),最后一个块可能只使用了部分slot。当请求长度不是16的倍数时,平均浪费约半个块。此外,KV Cache与激活值(Activation)之间的显存竞争也可能导致OOM。
| 碎片类型 | 产生原因 | PagedAttention的解决方式 | 残余影响 |
|---|---|---|---|
| 内部碎片(预留浪费) | 按最大长度预留 | 按需分配物理块 | 几乎消除 |
| 外部碎片(地址空洞) | 变长分配/释放 | 固定大小块+块表映射 | 完全消除 |
| 块内碎片(尾部空闲) | block_size固定 | 无法完全避免 | 平均浪费 < block_size/2 |
| KV与激活竞争 | 显存总量固定 | 通过gpu_memory_utilization预留比例 |
需合理配置 |
--block-size从默认16调小至8,减少块内碎片;但块越小,块表开销越大,需权衡。
3.4 实际案例:显存分配对比
假设GPU显存为40GB,gpu_memory_utilization=0.9,即可用于KV Cache的显存约36GB。模型为7B参数(权重约14GB),剩余22GB用于KV Cache。以block_size=16、每个token的KV Cache占用约0.5MB(以GQA-8B为例)计算:
可用物理块数 = 22GB / (16 × 0.5MB) ≈ 22 × 1024 / 8 = 2816 块
传统方式:每个请求预留2048 token → 每请求占用 2048×0.5MB = 1GB
最多并发 22 个请求(即使实际生成很短)
PagedAttention:假设平均实际生成512 token → 每请求占用 512×0.5MB = 256MB
最多并发 88 个请求(按平均长度估算)
实际吞吐提升约 3~4 倍
在sharegpt数据集上的实测中,vLLM相比HF Transformers的吞吐量提升达8~12倍,其中显存利用率提升贡献了约60%的增益,其余来自连续批处理(Continuous Batching)的调度优化。
3.5 常见误区与复盘
实际上块内碎片仍然存在。当请求长度分布集中在某个非16倍数附近时,浪费可能达到7%~10%。对于极端短请求(如长度1~5),浪费率甚至超过50%。此时应调小block_size。
该参数控制KV Cache可用的显存比例。设置过高会导致激活值(Activation)显存不足,引发OOM或频繁显存交换。建议从0.85开始,逐步上调至刚好不OOM的临界值。
当多个请求共享相同的系统提示词(System Prompt)或Few-shot示例时,vLLM的
--enable-prefix-caching可让这些请求共享前缀物理块。在ChatBot场景中,这能额外节省30%~50%的KV Cache显存。
复盘要点:在生产环境中,应结合请求长度分布、并发模式、模型参数量等因素,综合调整block_size、gpu_memory_utilization和max_num_seqs三个核心参数。通过监控vllm:num_requests_running和vllm:gpu_cache_usage_perc指标,可以实时判断显存分配是否健康。当cache使用率持续高于95%且请求排队增加时,说明KV Cache成为瓶颈,应考虑增加gpu_memory_utilization或减少max_num_seqs以降低块竞争。