一批大模型请求同时生成时,每条序列都要保存自己的 KV 缓存。请求长短不同,结束时间也不同。若服务先给每条请求预留一大段连续显存,短请求会空着不少位置,新请求还可能找不到足够大的连续区域。显存总量看着没用完,并发已经加不上去了。

我把 PagedAttention 原论文、Hugging Face 的分页注意力说明和连续批处理架构对照了一遍。PagedAttention 借用了操作系统分页的做法,把一条请求的 KV 缓存切成固定大小的块。逻辑上相邻的 token 可以放在不连续的物理块里,系统用块表记住它们的位置。

缓存不再要求排成一整段

请求刚进入时,服务只分配眼下需要的块。序列继续生成,再追加新块。注意力内核读取块表,找到这一条序列对应的 key 和 value。这样一来,已经释放的小块可以交给别的请求,空间浪费主要留在每条序列最后一个尚未填满的块。

块太大会减少管理开销,也会让最后一块空得更多。块太小能把空间切得细,块表和调度工作随之增加。Hugging Face 的实现文档还提醒,服务要为缓存之外的注意力掩码、中间结果和管理数据留空间。把 GPU 显存全算成 KV 块,运行时照样会顶满。

分页还有一个实用好处。多条生成若共享同一段提示词,系统可以让它们先引用相同的前缀块,等某条序列写入自己的新内容时再分开。连续批处理实现也会给共享块做引用计数,最后一个请求用完后才释放。前缀足够长、重复足够多时,这能减少预填充计算和缓存占用。

论文数字要带着测试条件读

vLLM 论文在其模型、硬件和请求分布下报告,相同延迟水平的吞吐量比当时比较的系统高 2 到 4 倍。这个结果说明内存管理会显著影响服务吞吐,却不等于每个项目上线 vLLM 都能得到同样倍数。模型结构、输入长度、输出长度和并发到达方式都会改写结果。

分页管理也不负责解决所有等待。长提示词的预填充仍然要算,单个请求的逐 token 解码仍受模型计算限制。若流量很小,系统大部分时间只处理一条短请求,减少碎片带来的收益自然有限。团队还要观察首 token 时间和单请求延迟,不能只挑每秒总 token 数。

比较服务方案时,可以准备三组真实负载。第一组以短问答为主,第二组放入长提示词,第三组混合长短请求并模拟突发流量。每组记录吞吐、延迟分位数、峰值显存和被抢占次数。PagedAttention 的价值会在这张表里出现,远比引用一个最高倍数可靠。

参考资料