【infra之路】PagedAttention

问题:朴素方式管 KV cache,浪费巨大

回忆模块一:每个请求在 decode 时,KV cache 会不断增长 (每生成一个 token 就追加一份 K、V)。问题来了------你事先不知道一个请求最终会生成多长。用户可能问一句话答 50 token 就结束,也可能让它写篇文章答 2000 token。

朴素的做法(vLLM 之前的框架就是这么干的):为每个请求预先分配一块连续的、按最大可能长度算的显存 。比如模型支持最大 2048 token,那就给每个请求都预留能装 2048 token 的 KV cache 连续空间。

这会造成两种严重浪费,记住这两个词,面试要用:

内部碎片(internal fragmentation) :你给一个请求预留了 2048 的空间,但它实际只生成了 50 token 就结束了------剩下 1998 个 token 的空间白占着、用不了。绝大部分预留空间都浪费了。

外部碎片(external fragmentation) :因为每个请求都要一块连续 的大空间,显存被切成大小不一的块,新请求来了即使总空闲显存够,却找不到一块足够大的连续空间塞进去------空间散落各处用不上。

研究测过,这种朴素方式下,KV cache 显存的实际利用率可能只有 20%-40%,六七成显存被碎片浪费了。而显存又是推理的命根子(还记得吗,KV cache 越大越能支持长序列和高并发)。浪费显存 = 直接限制了你能同时服务多少请求、能支持多长的对话。

这个问题你其实见过

想想阶段一你装系统、阶段二算显存------"要一块连续的大空间,但用不满"这个问题,和操作系统早期管内存遇到的问题一模一样 。早期程序也要连续内存,也面临碎片浪费。操作系统是怎么解决的?分页(paging)。PagedAttention 的名字就来自这里------它把 OS 的分页思想搬过来了。

方案:像 OS 分页一样管 KV cache

OS 分页的核心思想:不要求连续 。把内存切成固定大小的小块(页 page),程序需要多少就给多少页,这些页在物理内存里可以是分散的 ,用一张"页表"记录逻辑顺序到物理位置的映射。

PagedAttention 把这套照搬到 KV cache 上:

把 KV cache 切成固定大小的块(block) ,每块存固定数量 token 的 K、V(比如每块存 16 个 token)。一个请求的 KV cache 不再是一整块连续空间,而是按需一块一块地分配------生成了 16 个 token 就占一块,再生成 16 个再要一块。请求结束,它占的块立刻释放,还给别的请求用。

这些块在显存里物理上可以是分散的,vLLM 用一张**块表(block table)**记录"这个请求的第 N 段 token 在哪个物理块"------这就是 OS 页表的翻版。

为什么这样就解决了浪费

消灭内部碎片:按需分配,生成多少给多少块。一个请求只答 50 token,就占 4 块(50÷16≈4),不会预留 2048 的空间。浪费最多就是最后一块没填满的一点点(几个 token),从"浪费 1998"降到"浪费几个"。

消灭外部碎片:因为块是固定大小的,显存被切成一堆等大的块,任何空闲块都能拿给任何请求用------不存在"找不到连续大空间"的问题。新请求来了,凑几块空闲块就能跑。

结果:KV cache 显存利用率从 20%-40% 飙到接近 100% 。同样的显存,能装下多得多的请求的 KV cache → 能支持的并发量、序列长度大幅提升 → 吞吐大幅提高。这就是 vLLM 高吞吐的根本来源之一。


把它收成一张图,对照着记:

图里最后那行就是面试时的标准答法,背下来:PagedAttention 把 KV cache 切成固定块、按需非连续分配、用块表做映射,借鉴 OS 分页消除碎片,利用率接近 100%,从而支撑更高并发和更长序列。

再补一个额外的好处 ,它很重要、也常被追问------块可以共享 。既然 KV cache 是一块块的、靠块表映射,那如果多个请求有相同的前缀 (比如都用同一段 system prompt 开头),它们这段前缀的 KV 完全一样,就可以共用同几个物理块 ,不用各存一份。这就是你 vLLM 日志里看到的 enable_prefix_caching=True 的底层原理。它直接省显存、还省了重复计算前缀的时间。你看,PagedAttention 不只解决碎片,还顺带开启了"共享"这个新可能------这是分块设计带来的意外红利,跟 OS 里多个进程共享同一物理页(如共享库)又是一个对应。


PagedAttention 你现在理解到的层次,已经能在面试里讲透了:问题(两种碎片、利用率低)→ 方案(照搬 OS 分页、分块按需非连续 + 块表)→ 效果(利用率近 100%、高并发长序列)→ 红利(块共享 = prefix caching)。这套逻辑链比单纯说"它管理 KV cache 很高效"强太多,因为你能说清每一步的"为什么"。

而且你应该感受到了------这块之所以学得顺,是因为你前面的底子全用上了:阶段二的显存账(知道 KV cache 是什么、为什么占显存、为什么宝贵)、阶段一的 OS 概念(分页)。知识在这里复利了,这正是系统学习的回报。

相关推荐
腻害兔8 分钟前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
SeaTunnel23 分钟前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
碎光拾影38 分钟前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
Marst Code1 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
Miao121312 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
腻害兔2 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:支付模块 yudao-module-pay,一个让产品经理都看懂的支付中台设计
java·前端·vue.js·产品经理·ai编程
CRMEB系统商城3 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源
keyipatience4 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu
我的xiaodoujiao4 小时前
快速学习Python基础知识详细图文教程9--函数进阶
开发语言·python·学习·测试工具
weixin_408099674 小时前
2026 图片去水印 API 接口完全指南:一键去除图片水印(附 Python/Java/PHP/C# 示例)
java·python·php·图片处理·api调用·图片去水印·石榴智能