调查研究-222 PagedAttention 详解:vLLM 如何像操作系统一样管理 KV Cache
理解 vLLM PagedAttention:把 KV Cache 从连续显存变成可分页的系统资源
TL;DR
- 场景:在线 LLM 推理服务受 KV Cache 动态增长和碎片化限制,无法高并发承载请求
- 结论:vLLM 用 PagedAttention 把 KV Cache 当作分页系统资源管理,配合 continuous batching 把 LLM Serving 变成可调度的内存系统
- 产出:10 节系统化讲解(原理 / 块化收益 / 与调度协同 / 共享 / 局限 / 选型)+ 25 行版本矩阵 + 10 行错误速查卡
版本矩阵
| 功能 / 特性 | 状态 | 说明 |
|---|---|---|
| PagedAttention 论文(SOSP 2023, arXiv 2309.06180) | ✅ 已验证 | Kwon / Li / Zhuang / Sheng / Zheng / Yu / Gonzalez / Zhang / Stoica,UC Berkeley + Stanford + UCSD,SOSP 2023 最佳论文 |
| vLLM 0.10.x 持续更新 + 2025-09-05 Anatomy blog | ✅ 已验证 | GitHub 56.5k+ stars 领先其他开源推理引擎(DeepSpeed ~40k / SGLang ~18k) |
| vLLM vs HF Transformers 14-24× 吞吐提升 | ✅ 已验证 | PagedAttention 论文原始 benchmark 数据 |
| vLLM vs TGI 2.2-2.5× 吞吐提升 | ✅ 已验证 | PagedAttention 论文原始 benchmark 数据 |
| Continuous batching + PagedAttention 协同 | ✅ 已验证 | vLLM 核心设计,Orca iteration-level 调度继承 |
| Automatic prefix caching | ✅ 已验证 | vLLM 0.4+ 默认开启,--no-enable-prefix-caching 关闭 |
| Chunked prefill | ✅ 已验证 | vLLM 默认启用,长 prompt 切片处理 |
| Speculative decoding | ✅ 已验证 | vLLM 支持 EAGLE / Medusa / n-gram draft model |
| Guided decoding(FSM / xgrammar / outlines) | ✅ 已验证 | vLLM 内置结构化输出约束 |
| Function calling(auto/required/none) | ✅ 已验证 | vLLM ≥ 0.8.3 起支持 named tool_choice |
| Multi-LoRA serving | ✅ 已验证 | vLLM 内置,同 base 模型动态切换多 LoRA |
| Tensor parallel / Pipeline parallel / Sequence parallel | ✅ 已验证 | 1 GPU → 多机多 GPU,支持万亿参数模型 |
| P/D disaggregation(Prefill/Decode 分离) | ✅ 已验证 | DistServe / Mooncake 风格,vLLM 0.7+ 支持 |
| Multi-Step 调度(vLLM 2024 引入) | ✅ 已验证 | 与 chunked prefill 协同,降低 CPU overhead |
| FlashAttention / FlashInfer attention kernel | ✅ 已验证 | vLLM 默认,灵活切换 backend |
| 量化(FP8 / INT4 / INT8 / AWQ / GPTQ) | ✅ 已验证 | vLLM 支持多种权重 + KV cache 量化 |
| 多硬件支持(NVIDIA / AMD / Intel / Gaudi / TPU / AWS Trainium) | ✅ 已验证 | vLLM 0.6+ 全面扩展 |
| TensorRT-LLM v0.18.1 + CVE-2025-23254 | ⚠️ 注意 | <0.18.2 pickle 反序列化漏洞 CVSS 8.8,需升级 |
| SGLang v0.5.6 + RadixAttention 基数树 | ✅ 已验证 | LMSYS 出品,DeepSeek 官方推荐推理引擎之一 |
| SGLang vs vLLM prefix 命中率 23% → 96%(Qwen2-7B 多轮) | ⚠️ 项目方测试 | SGLang 博客 + 第三方对比,工作负载依赖明显 |
| TGI v1.0+ HFOIL 1.0 license(限制商业云托管) | ✅ 已验证 | 最后 Apache 2.0 版本是 0.9.4 |
| Ollama 个人 / 小并发本地推理 | ✅ 已验证 | 自动 API,模型库丰富 |
| llama.cpp 极致轻量 CPU / 边缘推理 | ✅ 已验证 | GGUF 量化,纯 CPU 流畅 |
| vLLM v0.10.2+ CVE-2025-62164(embeddings RCE) | ⚠️ 注意 | torch.load weights_only 边界检查,CVSS 8.8 |
| 连续批处理演进:Static → Orca → vLLM → Chunked → Sarathi → P/D 分离 → SGLang 零开销 | ✅ 已验证 | 2024-2026 调度层持续演进 |

vLLM 之所以成为 LLM Serving 里的标志性方案,核心不在于它改变了模型结构,也不在于它让每一次矩阵乘法突然变快,而在于它抓住了在线推理里最关键、最容易被低估的资源:KV Cache。
PagedAttention 的思想很直接:不要让每个请求的 KV Cache 占用一整段连续显存,而是像操作系统管理虚拟内存一样,把 KV Cache 拆成固定大小的 block,再用映射表把逻辑 token 位置映射到物理 block。
这个设计解决的是线上推理最现实的问题:请求长度动态变化,输出长度不可预测,请求结束时间不一致,显存容易碎片化,并发数最终被 KV Cache 限制。
理解 PagedAttention,不只是理解 vLLM 的一个特性,而是理解现代 LLM Serving 为什么越来越像一个小型操作系统。
一、vLLM 要解决的不是“模型不会跑”

在 vLLM 出现之前,模型当然也能跑。Hugging Face Transformers 可以 generate,FasterTransformer 可以做高性能推理,很多团队也能自己写一层服务,把模型包装成 API。
但“能跑”和“能高并发、低浪费、稳定地跑”不是一回事。
在线 LLM Serving 的核心难点在于动态性:
- 请求随机到达;
- prompt 长度不同;
- 输出长度不可预知;
- 请求可能中途取消;
- KV Cache 会随生成过程不断增长;
- 多个采样分支可能共享一部分前缀;
- 长 prompt、短 prompt、短输出、长输出混在同一个服务里。
如果只是低并发测试,一切看起来都正常。模型可以加载,接口可以返回,GPU 也在工作。但一旦进入真实在线场景,问题会集中暴露:显存被 KV Cache 挤满,请求开始排队,batch size 上不去,尾延迟变差,短请求被长请求拖住。
所以 vLLM 的切入点不是“模型推理这件事不会做”,而是“高吞吐 LLM Serving 需要一个能管理动态资源的系统”。
在这个系统里,KV Cache 就像内存;scheduler 像进程调度器;block table 像页表;请求像不断创建、运行、退出的进程。
二、传统 KV Cache 管理为什么浪费

假设每个请求都需要一段连续显存来存 KV Cache。系统通常会面对两种选择。
第一种是提前预留最大可能长度。比如请求最大上下文是 2048 token,系统就按 2048 token 预留 KV Cache。
这很安全,但非常浪费。用户可能只生成 50 个 token,剩余空间却被提前占住。线上服务里,大量请求不会真的用满最大长度,提前预留就会让显存利用率很低。
第二种是随着请求增长动态扩容。请求进入 prefill 后先占一段空间,decode 每生成一些 token,就继续扩容。
听起来更省,但实现复杂。因为 KV Cache 需要不断增长,如果原位置后面没有连续空间,就可能需要搬迁、重新分配,或者失败。
请求结束后也会留下碎片。A 请求释放了 300 token 空间,B 请求释放了 2000 token 空间,C 请求还在中间占用。显存总空闲看起来不少,但连续可用区域不一定适合新请求。
这就是内存碎片化。对 LLM Serving 来说,碎片化不是一个“工程洁癖”问题,而是会直接降低系统可承载的并发数。
PagedAttention 要解决的就是这件事:让 KV Cache 不再依赖连续显存。
| 传统做法 | 直接后果 | 线上影响 |
|---|---|---|
| 按最大长度预留 | 大量空间从未使用 | 并发数提前触顶 |
| 连续显存扩容 | 请求增长时容易搬迁或失败 | 调度复杂、延迟不稳 |
| 请求完成后释放连续段 | 空闲空间被切碎 | 总空闲不少但分配困难 |
| 多分支复制 KV | 公共前缀重复占用 | beam / sampling 成本高 |
三、PagedAttention 的基本思想

PagedAttention 把每个请求的 KV Cache 切成固定大小的 block。逻辑上,一个请求的 token 序列仍然是连续的;物理上,它的 KV block 可以分散在显存的不同位置。
系统维护一张 block table。它记录:某个请求的第几个逻辑 block,对应显存中的哪个物理 block。
这和操作系统虚拟内存很像。
程序看到的是连续虚拟地址。操作系统底层用页表把虚拟地址映射到不连续的物理页。
在 vLLM 中,请求看到的是连续 token 序列。PagedAttention 底层把 KV Cache 映射到不连续的物理 block。
这样一来,请求不再需要连续显存。只要全局 block pool 里还有空闲 block,请求就能继续分配。
可以把它拆成三层:
| 层 | 在操作系统里 | 在 PagedAttention 里 |
|---|---|---|
| 逻辑视图 | 进程看到连续虚拟地址 | 请求看到连续 token 序列 |
| 映射结构 | 页表 | block table |
| 物理存储 | 不连续物理页 | 不连续 KV block |
这不是一个表面类比。PagedAttention 的价值就在于把 KV Cache 从“连续大块显存分配问题”变成“固定粒度 block 管理问题”。
粒度固定之后,管理就简单了。申请时从全局 pool 拿 block;生成更多 token 时继续追加 block;结束时把 block 放回 pool;共享前缀时让多个逻辑 block 指向同一个物理 block。
四、block 化为什么能降低浪费

假设 block size 是 16 token。一个请求需要 100 token 的 KV Cache,它只需要 7 个 block。前 6 个 block 是满的,最后一个 block 可能只用了一部分。
这种浪费叫内部碎片。它仍然存在,但浪费范围被限制在最后一个 block,而不是整个最大预留空间。
相比按最大长度预留,block 化的浪费小得多。
更重要的是,block 化让请求的增长更自然。decode 阶段每生成一段 token,就可以按需分配新的 block。请求结束后,释放它占用的 block,回到全局 pool,后续请求可以立刻复用。
这就是 PagedAttention 论文里强调的核心问题:KV Cache 会动态增长和收缩,如果管理低效,就会因为碎片和重复复制浪费显存,从而限制 batch size。PagedAttention 用分页式管理降低浪费,让服务能容纳更多正在运行的请求。
它不是把注意力复杂度从根本上消掉了。长上下文仍然昂贵,decode 仍然要访问历史 KV。PagedAttention 的主要价值,是让同样的显存可以承载更多有效上下文、更少碎片、更少重复复制。
可以用一句话概括:
PagedAttention 不让 KV Cache 变小,而是让 KV Cache 更像一种可调度、可复用、可回收的系统资源。
这个变化非常关键。因为在线 Serving 里,很多时候不是模型权重先把显存吃完,而是动态增长的 KV Cache 限制了并发。
五、PagedAttention 和 continuous batching 是一组能力

PagedAttention 解决显存布局问题。Continuous batching 解决请求调度问题。
两者经常一起被讨论,因为它们在在线 LLM Serving 里互相需要。
Continuous batching 让请求可以在 decode step 中动态加入和退出。已经完成的请求退出,新请求补位,GPU 上的 running batch 不再是一批固定生命周期的请求。
这会显著提升 GPU 利用率,也能避免短请求被长输出请求长期拖住。
但调度越动态,KV Cache 的申请和释放就越频繁。如果底层显存管理仍然依赖连续大块分配,调度器越灵活,碎片问题越明显。
PagedAttention 让这种动态进出变得可控。请求完成后释放 block,新请求可以复用这些 block。调度器不需要等一整批请求一起结束,也不需要为每个请求提前保留巨大连续区域。
所以 vLLM 的关键不是单独一个技术点,而是一组协同:
- scheduler 决定谁进入 running batch;
- PagedAttention 管理 KV block;
- block table 维护逻辑和物理映射;
- free block pool 支撑快速分配和释放;
- prefix caching / sharing 降低重复 KV;
- preemption 在资源紧张时为系统兜底。
这也是为什么理解 vLLM 时,不能只看“用了什么 attention kernel”。真正重要的是它把调度和内存管理做成了一套系统。
六、PagedAttention 为什么适合共享 KV Cache

分页式 KV Cache 还有一个重要好处:共享更容易。
多个请求如果共享相同前缀,可以让它们的 block table 指向相同的物理 block。只有当后续 token 分叉时,才分配新的 block。
这类似 copy-on-write。
例如用户要求生成多个候选答案。它们共享同一个 prompt 的 KV Cache,然后在生成阶段走向不同分支。如果没有共享,每个候选都要复制一份 prompt KV Cache。共享后,公共前缀只存一次。
这对 beam search、parallel sampling、多候选生成、多轮对话 prefix 复用都有价值。
后来的 automatic prefix caching 也沿着这个方向继续发展:如果一个新请求和历史请求有相同前缀,就复用已经计算好的 KV block,让新请求跳过共享部分的 prefill 计算。
当然,共享并不是免费的魔法。系统需要维护 block 引用关系、hash、生命周期、淘汰策略和一致性。prompt 结构越稳定,命中越有价值;prompt 完全随机时,缓存命中率就会下降。
但从系统设计角度看,PagedAttention 给 KV Cache 共享提供了一个很自然的抽象:逻辑上是不同请求,物理上可以指向同一组 block。
这就是为什么它像操作系统。操作系统的页表不仅解决连续地址问题,也为共享内存、copy-on-write、进程隔离提供了基础抽象。PagedAttention 在 LLM Serving 里的角色也类似。
七、PagedAttention 不是什么

PagedAttention 很重要,但它不是万能答案。
第一,它不是新的模型结构。它不改变 Transformer 权重,也不改变模型能力。模型知道什么、推理能力如何、上下文窗口多大,本质上还是由模型本身决定。
第二,它不是让 attention 复杂度从根本上消失。长上下文仍然昂贵。decode 阶段仍然需要访问历史 KV,上下文越长,读取压力越大。
第三,它不是所有 workload 都有巨大收益。如果请求很少、上下文很短、并发很低,PagedAttention 带来的收益可能没有高并发场景明显。
第四,它不能替代良好的 scheduler。显存管理好,不代表 TTFT 一定低。如果长 prefill 独占 GPU,用户照样会等。如果 decode 请求过多,TPOT 仍然可能变差。
第五,它不替代容量规划。你仍然要看 KV Cache 使用率、block pool、prefix cache hit rate、preemption、TTFT、TPOT、P95/P99 和上下文长度分布。
所以更准确的说法是:PagedAttention 把 KV Cache 管理这个关键资源问题解决得更优雅,但完整的 Serving 仍然需要调度、缓存、切块 prefill、抢占、多 GPU 并行和监控体系一起工作。
八、什么时候 vLLM 很适合
vLLM 很适合以下场景。
第一,开放模型的在线推理服务,比如 Qwen、Llama、DeepSeek、Mistral 等。
第二,并发请求较多,需要提升吞吐、降低单位 token 成本,并且希望在同样硬件上容纳更多 running sequence。
第三,输入输出长度变化明显,传统静态 batch 或简单连续分配浪费较大。
第四,需要 OpenAI-compatible API,方便替换云 API 或接入现有应用。
第五,需要流式输出、prefix caching、LoRA serving、多 GPU tensor parallel、量化、投机解码、chunked prefill 等能力。
第六,需要快速搭建工程化推理服务,而不是从 CUDA kernel 开始自研。
对于本地 Qwen、A6000、ASR/LLM/TTS 链路、机器人语音系统这类场景,vLLM 是非常合理的默认选择。它能把 LLM 推理服务从“能跑”推进到“能承载并发”。
但 vLLM 不是所有场景唯一答案。
如果追求 NVIDIA GPU 上极致优化、强依赖 TensorRT engine、愿意接受更复杂构建流程,TensorRT-LLM 值得评估。
如果 workload 是复杂 Agent、多分支生成、结构化输出、共享 prefix 很多,SGLang 也值得评估。
如果在 Hugging Face 生态里,需要成熟的生产接口、Prometheus、OpenTelemetry 和模型生态集成,TGI 也可能更合适。
如果只是个人本地使用、小模型、低并发,Ollama 或 llama.cpp 可能更简单。
九、自研时能从 PagedAttention 学到什么
PagedAttention 的启发不只是“照抄一个 attention kernel”。
如果自研 GPU Serving,真正值得学的是三个原则。
第一,把动态请求资源变成固定粒度 block 管理。不要为每个请求预留大块连续资源。固定粒度不是为了形式漂亮,而是为了分配、释放、复用、监控都可控。
第二,把逻辑序列和物理存储解耦。请求视角可以连续,底层存储可以离散。这个抽象能让调度器和内存管理器分工更清楚。
第三,让调度器和内存管理器协同。Scheduler 决定谁运行,KV Cache Manager 决定是否有资源运行。两者割裂,就会出现 GPU 想跑但显存不够,或者显存空着但调度低效的问题。
这三个原则不只适用于 KV Cache,也适用于音频流 buffer、工具调用上下文缓存、多模态 embedding 缓存、RAG 文档上下文和 Agent 中间状态管理。
很多系统问题表面上是“算法慢”,实际是“资源没有被当成一等对象管理”。
十、核心结论
PagedAttention 的价值,是把 KV Cache 从“连续显存分配问题”变成“分页 block 管理问题”。
它降低碎片,减少浪费,让更多请求能同时留在 GPU 上,从而让 continuous batching 的效果更稳定。
vLLM 的强大不是单点魔法,而是围绕 LLM Serving 的真实瓶颈做了一套系统设计:请求动态调度、KV Cache 分页管理、流式 decode、长 prompt 控制、prefix 复用和多 GPU 扩展。
理解 PagedAttention,就是理解现代 LLM Serving 为什么越来越像操作系统。
当你开始把 KV Cache 看成需要分页、映射、共享、回收、监控和调度的资源时,你才真正进入了 LLM Serving 的工程视角。
参考资料
- vLLM Documentation, Paged Attention: https://docs.vllm.ai/en/latest/design/paged_attention/
- vLLM Blog, Easy, Fast, and Cheap LLM Serving with PagedAttention: https://vllm.ai/blog/2023-06-20-vllm
- Paper, Efficient Memory Management for Large Language Model Serving with PagedAttention: https://arxiv.org/abs/2309.06180
- vLLM Documentation, Automatic Prefix Caching: https://docs.vllm.ai/en/latest/features/automatic_prefix_caching/
- vLLM Blog, Inside vLLM: Anatomy of a High-Throughput LLM Inference System: https://vllm.ai/blog/2025-09-05-anatomy-of-vllm
- NVIDIA TensorRT-LLM Documentation: https://nvidia.github.io/TensorRT-LLM/
- Hugging Face Text Generation Inference: https://github.com/huggingface/text-generation-inference
- SGLang Documentation: https://docs.sglang.ai/
错误速查卡
| 症状 | 根因 | 定位 | 修复 |
|---|---|---|---|
| OOM 在长 prompt 高并发下 | KV Cache 按 max-len 提前预留,碎片化严重 | nvidia-smi 看显存是否随请求结束清空 |
升级 vLLM ≥ 0.6 + 启用 --enable-chunked-prefill + 调低 max-model-len |
| 同一 system prompt 多请求吞吐不涨 | prefix KV 没共享,每次重复 prefill | Prometheus 看 vllm:cache_hit_rate 指标 |
启用 --enable-prefix-caching,或迁移 SGLang RadixAttention |
| 长 prefill 请求阻塞 decode(TTFT 飙升) | prefill / decode 跑在同一 GPU 上,调度没分开 | nsys profiling + TTFT vs TPOT P99 对比 | 启用 chunked prefill;高负载场景走 P/D disaggregation |
| P99 延迟大幅抖动 | scheduler 与 KV Manager 割裂,preemption 频繁 | 监控 preemption_count / used_blocks |
升 vLLM 0.7+ 启用 Multi-Step 调度,扩显存或降并发 |
| vLLM 启动报 CVE-2025-62164(embeddings RCE 风险) | torch ≥ 2.8.0 稀疏张量检查默认关闭,torch.load(tensor, weights_only=True) 可绕过 |
pip show vllm torch,看 vllm ≥ 0.10.2 + torch ≥ 2.8.0 |
升级 vLLM 最新 patch 版本,或临时回退 torch < 2.8.0 |
| TensorRT-LLM Python executor RCE | pickle 反序列化漏洞 CVE-2025-23254(<0.18.2) | 看 trtllm 版本 < 0.18.2 + IPC ZeroMqQueue |
升 TensorRT-LLM ≥ 0.18.2 |
| 商业部署 TGI 收到 HF 法务函 | TGI v1.0+ 改 HFOIL 1.0 license,限制未授权云托管 | 看 TGI 版本 + LICENSE | 退回 TGI 0.9.4(最后 Apache 2.0),或改用 vLLM / SGLang |
| 短请求被长请求拖住(P99 高) | 旧 static batching / 一次性 batch | 看 running batch 内最大请求长度 | 升 vLLM 启用 continuous batching + chunked prefill |
| 显存够但 batch size 上不去 | KV 碎片化严重,free blocks 多但连续可用少 | 监控 free_blocks 与最大连续块 |
切到 vLLM PagedAttention 或 SGLang RadixAttention |
| Ollama / llama.cpp 上生产后崩 | 误把本地框架用到了高并发生产 | 看 QPS / 并发 / GPU 利用率 | 高并发场景换 vLLM / TensorRT-LLM / SGLang |
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)