图 1:本文封面,操作系统分页思想搬进 KV Cache 管理。
先说明属性:这是一篇经典题解析,题目出自本地历史面试资料整理,与任何公司的当前招聘无关。大模型推理服务面试里,「vLLM 为什么快」几乎必问,而答案的核心就是 2023 年 vLLM 论文提出的 PagedAttention——一道把操作系统虚拟内存思想搬进 GPU 显存管理的经典设计题。
先搞清敌人:KV Cache 为什么难管。
自回归解码时,每生成一个 token,都要把它之前所有 token 的 Key、Value 张量留在显存里供注意力读取,这就是 KV Cache。它有两个讨厌的性质:一是大,单个长序列就能吃掉上 GB 级显存;二是大小动态变化,序列长度不可预测,生成过程中还在不断变长。传统推理框架的做法是按「最大可能长度」为每条序列预留一整块连续显存。后果是双重浪费:序列实际没长到上限,预留的空间闲置(内部碎片);显存里东一块西一条的空档凑不出一整块连续区(外部碎片)。论文给出的实测结论是:现有系统因此浪费 60% 到 80% 的 KV Cache 显存。显存被浪费,能同时容纳的并发序列就少,吞吐直接受限——推理服务的瓶颈首先是显存,其次才是算力。
破局思路:把「分页」整套搬过来。
PagedAttention 的类比干净漂亮:KV 块就是操作系统的页,token 就是字节,序列就是进程。具体三件套:
按需分配。不再为每条序列预留最大长度,而是把 KV Cache 切成固定大小的块(比如每块装 16 个 token 的 KV),解码一个 token 才占一个槽,块满了才申请新块。显存占用从「按上限预付」变成「按实际用量付费」。
块表映射。每条序列维护一张块表,记录逻辑块号到物理块号的映射。物理块在显存里可以完全不连续,块表这层间接让它们对外表现成连续序列——这正是虚拟内存里页表的角色,外部碎片因此彻底消失,浪费只剩最后一个没填满的块,即尾块内部碎片。论文报告分页后浪费率压到 4% 以下。
写时共享。并行采样、束搜索这类场景里,多条输出序列共享同一段提示词前缀。不同序列的逻辑块可以映射到同一个物理块,配合引用计数跟踪共享者数量,某条序列要往共享块里写新内容时才复制一份(Copy-on-Write)。前缀的 KV 只存一份,共享开销大幅下降。
用模拟把浪费率算出来。
下面这段程序模拟 1000 条长度高度不均的序列(七成短请求、少量超长请求),对比「按 4096 上限连续预留」和「按 16 token 块按需分配」两种账(Node.js 22.15.0,node paged.js):
const MAX_LEN = 4096, BLOCK = 16, N = 1000;
function randLen() { // 真实服务里长度分布高度倾斜
const r = Math.random();
if (r < 0.7) return 32 + Math.floor(Math.random() * 480);
if (r < 0.95) return 512 + Math.floor(Math.random() * 1536);
return 2048 + Math.floor(Math.random() * 2048);
}
let reserved = 0, paged = 0, used = 0;
for (let i = 0; i < N; i++) {
const len = randLen();
used += len;
reserved += MAX_LEN; // 每条都按上限预留
paged += Math.ceil(len / BLOCK) * BLOCK; // 按需分配,浪费只在尾块
}
console.log('连续预留浪费率:', ((1 - used / reserved) * 100).toFixed(1) + '%');
console.log('分页分配浪费率:', ((1 - used / paged) * 100).toFixed(1) + '%');
console.log('同显存可多装并发:', (reserved / paged).toFixed(1) + 'x');
实测输出:
连续预留浪费率: 84.2%
分页分配浪费率: 1.1%
同显存可多装并发: 6.3x
数字和论文「浪费 60%~80% → 压到 4% 以下」的结论同向:分页把浪费几乎清零,省下的显存全部转化为可并发服务的序列数,这就是吞吐成倍提升的来源。
图 2:连续预留与分页管理的显存对比,三张机制卡对应三件套。
答题主线:先讲敌人,再讲三件套。
建议的回答顺序:先用「大且动态」讲清 KV Cache 为什么难管、传统预留的双重碎片浪费;再按「按需分配、块表映射、写时共享」逐条讲机制,每条都点明它消灭的是哪种浪费;最后落到收益——显存利用率提升意味着同一张卡能批处理更多序列,吞吐上去、延迟不变。被追问时,「块表对应页表、序列对应进程」这个类比本身就是加分项。你在部署推理服务时撞到的是显存墙还是算力墙?欢迎聊聊你的瓶颈。