文章

PagedAttention 生产实战:用分页 KV Cache 提升 LLM Serving 吞吐

系统讲解 PagedAttention 如何通过分页 KV Cache 管理缓解大模型推理中的显存碎片与过度预留问题,帮助工程团队提升吞吐、降低延迟波动,并给出生产上线检查清单与监控策略。

背景问题:为什么 KV Cache 会成为推理系统的隐性瓶颈

Transformer 自回归生成时,每生成一个 token 都需要访问前面所有 token 的 Key 和 Value。为了避免每一步重新计算历史上下文,推理系统会将中间结果缓存下来,这就是 KV Cache

KV Cache 有三个典型特征:

  1. :随层数、hidden size、head 数、上下文长度和 batch size 线性增长。
  2. 动态:请求长度不同,输出长度不可预知,显存需求持续变化。
  3. 强占显存:KV Cache 通常驻留在 GPU 显存中,直接挤压可并发请求数量。

在没有分页管理时,系统往往需要为每个请求预留一段连续显存,或按最大长度估算空间。这会带来两类浪费:

  • 内部碎片:序列最后一段没有填满,但对应显存已经分配。
  • 外部碎片:显存还有总量,但不一定有足够大的连续空间给新请求。

当请求长度分布很不均匀时——如同一个服务同时处理短问答、长文档总结、RAG 检索问答和多轮 Agent 任务——这个问题会进一步放大。即使 GPU 看起来还有显存,调度器也可能无法安全地塞入更多请求。

核心原理:把 KV Cache 当成”分页内存”管理

PagedAttention 的设计可以用三个对象理解:

  • Logical blocks:一个请求在逻辑上连续的 token 块。
  • Physical blocks:GPU 显存中真实分配的 KV Cache 块。
  • Block table:把逻辑块映射到物理块的表。

普通 KV Cache 管理更像”为一个请求分配一整段连续数组”。PagedAttention 则更像操作系统的虚拟内存:一个请求看到的是连续 token 序列,但底层显存块可以不连续。

Request tokens: [ t0 t1 t2 t3 ][ t4 t5 t6 t7 ][ t8 t9 ... ]
Logical block id: [ block 0 ][ block 1 ][ block 2 ]
Block table:
  block 0 -> physical block 17
  block 1 -> physical block 03
  block 2 -> physical block 42

当请求继续生成 token,系统按需申请新 block;当请求结束,block 释放回池中;当多个请求共享同一段前缀,block 也有机会复用。

这带来的好处不是”attention 算法复杂度变成常数”,而是显存管理效率提升。它让系统能更稳定地把 GPU 显存转化为有效 batch,而不是浪费在碎片和保守预留上。

与连续批处理的关系:PagedAttention 不是单点优化

PagedAttention 常和 continuous batching 一起出现,但二者不是同一件事。

技术解决的问题
Continuous batching调度问题:请求完成时新请求可立刻进入 batch,不必等整个 batch 结束
PagedAttention显存组织问题:请求进入、退出、增长时,KV Cache 按块动态分配和回收

二者结合后,服务端可以更大胆地做动态调度:

Incoming requests

Scheduler groups active sequences

Paged KV blocks allocated on demand

Attention kernel reads blocks by block table

Completed requests release blocks

New requests fill freed capacity

如果只有 continuous batching 而没有高效 KV Cache 管理,系统仍可能被显存碎片卡住。如果只有 PagedAttention 而没有合理调度,显存效率也不一定能转化为吞吐收益。

工程落地:适合哪些生产场景

PagedAttention 最适合以下类型的服务:

1. 请求长度差异大的在线推理

例如同一个 LLM API 同时处理:

  • 短指令问答
  • 长文档总结
  • RAG 检索增强问答
  • 多轮会话
  • Agent 工具调用链

这类负载的上下文长度分布不稳定,传统连续显存分配很容易浪费空间。

2. 多并发、吞吐优先的模型服务

如果目标是提高单卡或多卡吞吐,PagedAttention 可以帮助系统容纳更多 active sequences。它不保证每个请求都更快,但通常能改善整体容量与稳定性。

3. 长上下文和 prefix reuse 场景

长系统提示词、固定模板、多轮会话和 RAG 管线都可能出现共享前缀。分页 KV Cache 为块级共享、复用和缓存淘汰策略提供了基础。

4. 多输出采样

并行采样时,多个候选输出可能共享同一段 prompt 的 KV Cache。块级共享可以减少重复存储,提高并行生成效率。

上线架构:从”能跑”到”可控”

生产环境不要只把 vLLM、TGI 或 TensorRT-LLM 启动起来就结束。更稳妥的方式,是把 PagedAttention 放入整体推理架构中治理。

推理服务层

推理服务需要明确:

  • 模型上下文长度上限
  • 最大 batch token 数
  • 最大并发序列数
  • block size
  • prefill 和 decode 阶段的调度策略
  • 是否启用 prefix caching 或 KV cache reuse

路由层

如果有多个推理实例,应避免完全随机路由。对于共享系统提示词、多轮会话或相同知识库任务,可以考虑 KV-aware routing,让更可能命中缓存的请求进入同一个实例或同一组实例。

限流层

KV Cache 不是无限资源。限流不应只按 QPS 计算,还应考虑:

  • prompt token 数
  • max output token 数
  • 当前显存压力
  • 请求是否为长上下文
  • 是否允许流式输出

更合理的做法是建立 token budget,而不是只限制请求数。

常见误区

误区一:PagedAttention 等于降低所有请求延迟

PagedAttention 的主要收益是显存效率和吞吐容量。单个短请求在低并发情况下,未必能明显变快。甚至因为多了一层 block table 访问和 kernel 适配,在某些场景下还可能有额外开销。

判断效果时,不要只看单请求 benchmark,要看生产负载下的:

  • TTFT(Time to First Token)
  • TPOT(Time per Output Token)
  • tokens/s
  • GPU utilization
  • OOM 次数
  • p95 / p99 延迟

误区二:block size 越小越好

block 越小,显存浪费越少,复用粒度越细;但 block 太小可能增加管理开销,也可能影响 kernel 访问效率。block size 是典型权衡项:

block size可能收益可能代价
较小更细粒度分配,更少尾部浪费,更容易局部复用元数据更多,调度和访问开销更高
较大kernel 访问可能更友好,管理开销更低尾部浪费更高,复用命中条件更粗

实际选择应结合模型、上下文长度分布、并发模式和框架默认值测试。

误区三:只要启用 PagedAttention,就不需要容量规划

PagedAttention 能减少浪费,但不能改变 KV Cache 线性增长的事实。长上下文、长输出、高并发仍会让显存成为瓶颈。上线前仍然要做容量模型。

可以用以下简化公式做初步估算:

KV cache memory ≈ layers × 2 × hidden_size × tokens × bytes_per_element × batch_factor

这里的 2 对应 Key 和 Value。真实实现还会受到 GQA/MQA、量化、张量并行、padding、block size 和框架内存池影响,所以该公式只能用于方向性判断。

上线检查清单

1. 负载画像

上线前先统计真实请求,而不是只用平均值:

  • prompt token p50 / p95 / p99
  • output token p50 / p95 / p99
  • 多轮会话比例
  • RAG 请求比例
  • 共享 system prompt 比例
  • 流式输出比例

2. 压测矩阵

至少覆盖以下组合:

场景观察重点
短 prompt + 短输出调度开销是否可接受
长 prompt + 短输出TTFT 和 prefill 压力
短 prompt + 长输出decode 阶段 KV 增长
长 prompt + 长输出OOM、p99 延迟、吞吐上限
多轮会话prefix reuse 和缓存命中
RAG 模板系统提示词和检索内容的复用机会

3. 监控指标

建议至少监控:

  • GPU 显存使用率
  • active sequences
  • waiting queue length
  • prefill tokens/s
  • decode tokens/s
  • TTFT p50 / p95 / p99
  • TPOT p50 / p95 / p99
  • cache hit ratio
  • block allocation failure
  • eviction count
  • OOM count
  • request cancellation rate

4. 回滚策略

推理系统变更要保留回滚路径:

  • 保留旧版本 serving 配置
  • 控制单实例灰度比例
  • 将长上下文请求单独路由
  • 对 max tokens 设置保守上限
  • 出现 OOM 或 p99 激增时自动降级

适用边界

PagedAttention 对以下场景收益可能有限:

  1. 低并发、短上下文服务:显存碎片不是主要问题。
  2. 严格追求单请求最低延迟:需要同时优化 kernel、batch、模型量化和调度。
  3. 缓存复用很少的随机请求:block sharing 价值有限,但按需分配仍可能有用。
  4. 框架或模型 attention 类型特殊:需要确认当前 serving 框架是否支持对应模型结构。

对于新模型,尤其是混合 attention、sliding window attention、Mamba-like 结构或特殊位置编码模型,需要检查框架文档中的兼容性说明,不要简单假设所有模型都能获得同样收益。

参考资料

常见问题

PagedAttention 和普通 attention 的区别是什么?
普通实现通常要求 KV Cache 在显存中连续存放,或需要按最大长度做较保守的预留。PagedAttention 将 KV Cache 拆成固定大小的 block,通过 block table 把逻辑序列映射到非连续的物理显存块,从而降低碎片和预留浪费。
PagedAttention 一定能降低单个请求延迟吗?
不一定。它更常见的收益是提升吞吐、降低显存浪费、减少 OOM、提升高并发下的稳定性。单请求延迟还取决于模型大小、上下文长度、batch 策略、kernel 实现、GPU 型号和是否启用 prefix caching。
生产环境上线 PagedAttention 最应该监控什么?
重点监控 GPU 显存占用、KV Cache 使用、block 分配失败、cache hit ratio、TTFT、TPOT、tokens/s、OOM 次数和 p95/p99 延迟。只看平均延迟很容易掩盖长上下文请求带来的尾部风险。