PagedAttention
PagedAttention 以固定块管理 KV Cache,减少变长请求造成的显存碎片和浪费。它把逻辑序列的 KV 映射到若干固定大小的物理块上,按需分配而非一次性预留最大长度。
PagedAttention 由 vLLM 团队在 Efficient Memory Management for Large Language Model Serving with PagedAttention(SOSP 2023)中提出。它的由来是 KV Cache 的碎片问题:传统做法为每个请求预留一段「最大长度」的连续显存,请求实际生成的 token 数却不可预知,于是预留空间要么不够、要么大量闲置,且不同请求反复分配释放会在显存中留下无法利用的碎片。PagedAttention 借鉴操作系统虚拟内存的分页思想,把 KV Cache 切成固定大小的块 (block),通过一张块表把逻辑位置映射到任意物理块,请求随生成逐步申请块、按块回收,从而把显存利用率提升到接近无浪费的水平。
快速开始¶
监控 KV block 利用率、请求排队和 cache 命中,先在变长并发负载上比较吞吐。
- 启用并配置:使用支持 PagedAttention 的运行时(如 vLLM),确认 block 大小与显存配额。vLLM 通过
gpu_memory_utilization控制可用的显存比例,KV block 大小默认约 16 个 token。 - 构造负载:混合长短请求并发发送,观察不同并发下的吞吐与排队情况。
- 监控指标:记录 block 利用率、请求排队时长与 cache 命中,定位碎片或浪费。
验证成功的关键是在相同显存下能承载更多并发请求,吞吐提升且排队减少。若利用率始终偏低,检查 block 大小与请求长度分布是否匹配,参数语义以 vLLM 文档 对应版本为准。
原理¶
逻辑序列映射到非连续物理块,类似虚拟内存分页。请求不再预留「最大长度」的连续显存,而是随生成逐步申请新块,短请求只占用少量块,释放时按块回收。
设 block 大小为 \(B\) 个 token,序列已生成 \(n\) 个 token,则该序列占用的块数为 \(\lceil n/B\rceil\)。每个请求持有一张块表 \(T\),其中第 \(i\) 个逻辑块存放于物理块 \(T[i]\),attention 内核在计算时按块表把非连续物理块拼接成逻辑序列。以 \(B=4\)、\(n=10\) 为例,块表形如:
即前 4 个 token 的 KV 在物理块 7,中间 4 个在物理块 21,末尾 2 个在物理块 5,物理块之间不必连续。因为末块只用了 2/4,仍存在少量内部浪费,但已远小于预留整段最大长度的外部浪费。
请求可按需分配、释放或共享块。分配时按需申请块,结束时整块回收,避免频繁分配导致的外部碎片;共享则借助「写时复制」思想,让并行采样、beam search 或多个请求复用同一份前缀 KV,只在内容真正变化时才复制对应块。原论文报告 KV Cache 浪费可降到 4% 以内。
块大小的选择有取舍:块太小则块表与寻址开销上升,块太大则在序列尾部留下未用空间,造成内部浪费。实现上 attention 内核需能按块表拼接非连续 KV,这是与连续 KV 实现的主要区别。
案例¶
大量短长混合会话导致连续分配失败,分页后可提高并发;但 block 大小过大仍会浪费尾部空间。
以多轮对话服务为例,连续分配方式为每个请求按最大长度预留 KV,长请求与大量短请求混合时显存很快耗尽或产生碎片,导致分配失败、请求排队。改用分页后,显存利用率提高,可承载更多并发。
代价是块大小若与请求长度分布不匹配,尾部块可能大量闲置。例如块过大而多数请求只多出少量 token,浪费明显;此时可调小块大小,但需重新基准测试寻址与调度开销。
常见失败点是显存利用率没提升或吞吐下降,排查时同时看 block 利用率、尾部浪费比例与并发上限,必要时调整块大小与显存配额。