vLLM如何用PagedAttention和连续批处理解决KV缓存内存浪费
作为正在把大模型部署到生产环境的工程师,你最头疼的问题往往不是模型本身跑不起来,而是GPU内存被KV缓存吃掉后,能同时服务的用户数量远低于预期。你花重金买了顶级GPU,却发现实际吞吐量只有理论值的几分之一,成本居高不下。
Amit Shekhar(Outcome School创始人)在最新技术解析中,用极清晰的机制拆解,完整还原了vLLM解决这个核心痛点的全过程。它不是简单地“更快推理”,而是通过操作系统式的内存分页思想 + 动态批处理,彻底改变了LLM serving的内存利用方式。
我起初以为LLM serving的瓶颈主要在于模型计算速度,后来深入KV缓存的生命周期才发现,真正的限制其实是内存管理:天真的做法会为每个请求预留远超实际需要的连续大块内存,导致大量浪费和碎片化。vLLM正是针对这个痛点,用两个核心机制把GPU利用率拉到极致。
LLM serving的基本流程与KV缓存
Serving一个LLM,就是让成千上万用户同时发请求,模型在GPU上处理后返回结果。GPU内存既要装模型权重,又要为所有正在生成的请求保存KV缓存。
简单回顾两个阶段:
- Prefill:模型一次性读完整个prompt,计算并存储所有token的KV值。
- Decode:模型逐个token生成回复,每生成一个新token,都需要前面所有token的KV值来计算注意力。
KV缓存就是这些“笔记”的集合——每个token对应一组Key和Value。Decode阶段每多生成一个token,KV缓存就多一组笔记,而且必须一直留在GPU内存里,直到这个请求结束。
KV缓存的大小随回复长度线性增长。这就是问题所在:它直接决定了你能同时跑多少个并发请求。
天真做法为什么严重浪费内存
最简单的serving引擎会这样做:请求进来时,因为不知道回复会多长,就为它一次性预留一个能装下最长可能回复(比如2000 token)的大块连续内存。
结果呢?
- 大多数回复其实很短(比如只有50 token),剩下1950 token的空间被白白占着,无法给其他请求用 → 过度预留(over-reservation)。
- 不同请求的内存块大小不一、散落在显存里,中间留下很多小碎片 → 碎片化(fragmentation)。即使总空闲内存看起来不少,也拼不出能给新请求用的大块连续空间。
最终效果是:GPU明明还有很多内存,却因为管理方式低效,只能服务很少的用户。你在为昂贵的硬件买单,却只用到了很小一部分。
vLLM的核心创新:PagedAttention
vLLM的第一个杀手级特性是PagedAttention,灵感直接来自操作系统对内存的管理。
操作系统把内存分成固定大小的页(pages),程序需要内存时按需分配页,页可以不连续存放,只用一个页表记录映射关系。
vLLM对KV缓存做了完全一样的事:
- 把KV缓存内存切成固定大小的块(blocks)(例如每个块存16个token的KV值)。
- 请求需要更多空间时,按需分配新块,不要求块必须连续。
- 用一个**块表(block table)**记录每个请求当前占用了哪些块,以及顺序。
当请求结束时,它占用的所有块立刻被释放回共享池,供其他请求使用。
这样做的效果是:
- 几乎没有过度预留:只在真正需要时才分配块。
- 几乎没有碎片化:所有块大小相同,任何空闲块都能立刻被任何请求使用。
PagedAttention带来的额外红利:内存共享
块化之后,vLLM还能实现内存共享,这是天真做法几乎做不到的。
两个典型场景:
- 相同前缀(identical prefixes):很多请求以同样的长系统提示开头(比如“你是一个礼貌的汽车经销商客服”)。vLLM只为这个共享前缀存储一次KV块,所有请求的块表都指向同一组块。
- Beam Search:模型同时探索多条候选路径,这些路径前期完全相同,后期才分叉。共享前缀的块能节省大量重复存储。
这让同一块GPU内存能服务更多请求,尤其适合Agent系统(Agent每一步往往重复发送大量相同指令)。
连续批处理:让GPU计算永不空闲
vLLM的第二个核心机制是连续批处理(Continuous Batching),解决的是GPU计算时间的浪费。
传统静态批处理:把一批请求凑齐后一起跑,必须等所有请求都生成完才能处理下一批。短回复的请求早早结束,却要空等长回复的请求,GPU槽位白白闲置。
连续批处理则完全不同:在Decode的每一步(每生成一个token),vLLM都会检查是否有请求刚刚结束。如果有,立刻把这个请求踢出当前批次,同时从等待队列拉一个新请求进来填补空位。
结果是:GPU的计算资源几乎永远处于满载状态,没有因为“等最慢的那个”而浪费时间。
PagedAttention和连续批处理完美互补:
- PagedAttention让内存块能即时释放和复用。
- 连续批处理让刚释放的内存和计算槽位立刻被新请求占用。
两者结合,把GPU的内存和算力利用率同时推到极高水平。
vLLM的实际收益与落地场景
- 吞吐量大幅提升:单位时间内能处理更多token和更多并发请求。
- GPU利用率显著提高:内存和计算双双接近满载。
- 单请求成本大幅降低:同样硬件能服务更多用户。
- 易于接入:提供OpenAI兼容的API服务器,现有应用只需改个endpoint就能用上。
真实世界里,vLLM特别适合两类场景:
- 高并发聊天应用(大量用户同时对话)。
- Agent系统(大量短步骤、重复前缀的调用)。
它已成为目前最受欢迎的开源LLM serving引擎之一,尤其适合想在自有GPU上高效运行开源模型的团队。
天真serving vs vLLM核心对比
| 维度 | 天真静态批处理 + 连续大块KV缓存 | vLLM (PagedAttention + 连续批处理) |
|---|---|---|
| 内存分配方式 | 每个请求预留超大连续块 | 按需分配固定大小块,可不连续 |
| 内存浪费 | 严重过度预留 + 碎片化 | 接近零浪费,可共享相同前缀 |
| GPU计算利用率 | 短请求早结束导致槽位空闲 | 每步动态换入新请求,计算几乎不间断 |
| 并发能力 | 受限于浪费的内存 | 相同硬件下可服务远更多请求 |
| 适用场景 | 低并发、回复长度可预测 | 高并发聊天、Agent系统、回复长度差异大 |
| 实现复杂度 | 简单 | 需要块表管理,但对外提供标准API |
vLLM的本质是把操作系统内存管理的成熟思想,精准迁移到了LLM的KV缓存上,同时用动态批处理解决了计算时间的碎片问题。它没有改变模型输出的质量,只是把你为GPU付出的每一分钱都用到了极致。
如果你正在搭建或优化LLM serving系统,下一次部署时不妨直接试试vLLM。它的OpenAI兼容接口让切换成本极低,而带来的吞吐量和成本改善往往是数量级的。
在你的场景里,当前最大的瓶颈是内存碎片化还是计算槽位空闲?欢迎在评论区分享你的实际痛点。
我是紫微AI,在做一个「人格操作系统(ZPF)」。后面会持续分享AI Agent和系统实验。感兴趣可以关注,我们下期见。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)