PagedAttention:把 KV cache 分页
将逻辑连续的 token 缓存映射到分散的物理块,减轻显存碎片与重复存储。
相关概念
工程问题#
生成长度动态增长,按最大长度预留连续缓存会浪费显存,并限制可同时服务的请求数。
实际实现#
2023 年原始设计用块表连接逻辑块和物理块;注意力内核按块表读取,共享块用引用计数与写时复制管理。
处理流程#
- 为序列建立逻辑块表
- 按需分配物理 KV 块
- 内核经块表读取不连续缓存
- 共享块被修改时复制,结束后释放引用
源码片段#
固定版本 · 原文摘录vllm/core/block_manager.pyv0.1.7 · 早期 PagedAttention 实现 · L127–L139
127 # We want to append the token to the last physical block.128 last_block = block_table[-1]129 assert last_block.device == Device.GPU130 if last_block.ref_count == 1:131 # Not shared with other sequences. Appendable.132 return None133 else:134 # The last block is shared with other sequences.135 # Copy on Write: Allocate a new block and copy the tokens.136 new_block = self.gpu_allocator.allocate()137 block_table[-1] = new_block138 self.gpu_allocator.free(last_block)139 return last_block.block_number, new_block.block_numberBlockSpaceManager.append_slot
追加 token 时,若末块由多个序列共享,分配新物理块并替换块表末项,降低旧块引用。返回值是旧、新块编号,交由后续执行路径安排复制;此 Python 片段没有直接复制 GPU tensor。它展示早期写时复制管理,不是当前 V1 前缀缓存实现。
PYTHONApache-2.0
论文仍以 SOSP 2023 为依据;代码另取固定 v0.1.7 作为早期实现对照,不宣称该 tag 就是论文评测所用 commit。
收益与取舍#
工程分析带来的收益
- 避免为整个输出预留连续空间
- 共享 prompt 或采样分支的缓存
付出的代价
- 末尾块仍存在内部碎片
- 需要支持块表寻址的内核及共享状态维护
可比较的选择
连续 KV 缓冲区寻址直接,但预留或扩容成本随请求长度与并发形态变化。
版本与适用范围#
历史设计案例:仅说明 2023 年论文中的分页与写时复制机制,不代表当前 vLLM 所有后端或 V1 调度实现。
参考来源#
源码、官方文档与原始论文相关实现与比较#
2 个相关案例把上下文身份编码进块哈希,让重复请求共享已经计算的 KV cache。
附源码片段 · 缓存与复用
vLLM V1 每轮分配 token 预算,先继续运行中的请求,再尝试接纳等待者;KV 块不足时抢占请求,把它放回等待队列。
附源码片段 · 调度与资源分配