Efficient Memory Management for Large Language Model Serving with PagedAttention

把操作系统的分页思想引入 KV Cache 管理,显著提升大模型服务吞吐,是现代推理系统论文中的关键代表。

年份与会议

2023 · arXiv

作者

Woosuk Kwon、Zhuohan Li、Siyuan Zhuang、Ying Sheng、Lianmin Zheng、et al.

主题

推理系统

阅读时长

约 3 分钟

收录时间

2023/09/12

标签

原文链接

https://arxiv.org/abs/2309.06180

为什么 vLLM / PagedAttention 会成为推理系统必读论文

很多大模型论文关注的是模型本身,但真正到了线上服务阶段,工程团队很快会发现:模型强不强只是第一步,能不能稳、快、省地服务大量请求才是真正决定产品体验的环节。

vLLM 论文之所以重要,是因为它抓住了 LLM serving 里一个极其现实、又长期被低估的问题:

KV Cache 很大,而且会随着请求动态增长和释放;如果管理不好,显存会被严重浪费。

PagedAttention 的贡献,不是提出一个更强的模型,而是让现有模型在同样硬件上更高效地被服务出来。这类工作在真实产品里往往价值巨大。

背景:为什么现有服务系统会被 KV Cache 拖垮

在自回归生成中,模型会为每个请求、每一层、每个历史 token 保存 K/V 缓存。随着上下文增长,这块缓存会越来越大。

问题在于,线上请求是高度动态的:

  • 有的 prompt 很短
  • 有的 prompt 很长
  • 有的请求很快结束
  • 有的请求会持续生成很多 token

如果系统为每个请求分配连续的大块显存,很容易产生两个问题:

  1. 碎片化严重
  2. 明明有总量可用显存,却因为分配方式不灵活,塞不进更多请求

这也是为什么很多服务系统理论上 GPU 很强,实际吞吐却上不去。

核心想法:把 KV Cache 当成“分页内存”来管理

PagedAttention 的灵感非常直观,来自操作系统中的虚拟内存和分页机制。

与其为每个请求分配一整块连续显存,不如:

  • 把 KV Cache 切成较小的固定页块
  • 通过页表式映射组织这些块
  • 让请求的逻辑序列与物理内存位置解耦

这样做的直接收益是:

  • 减少内存碎片
  • 更灵活地扩展和回收缓存
  • 更容易支持动态长度请求
  • 更容易做缓存共享与复用

这个想法看上去像系统细节,但它几乎直接决定了能同时跑多少请求。

把“连续大块显存”与“分页式 KV Cache”放在一起看,PagedAttention 的价值会更直观:

连续显存分配与分页式 KV Cache 对比图 左侧是连续分配 KV Cache 导致不同请求结束后形成碎片;右侧是分页式管理,逻辑序列通过页表映射到物理页块,显存回收和复用更灵活。 连续分配 KV Cache PagedAttention
  <rect x="86" y="108" width="320" height="44" rx="10" fill="#e8f1ff" stroke="#98b7e1" />
  <text x="246" y="136" text-anchor="middle" font-size="17" font-weight="700">请求 A 的连续缓存</text>
  <rect x="86" y="164" width="188" height="44" rx="10" fill="#eef6e8" stroke="#a8c48e" />
  <text x="180" y="192" text-anchor="middle" font-size="17" font-weight="700">请求 B</text>
  <rect x="292" y="164" width="114" height="44" rx="10" fill="#ffffff" stroke="#d1d5db" />
  <text x="349" y="192" text-anchor="middle" font-size="14" fill="#8b4b4b">空洞 / 碎片</text>
  <rect x="86" y="220" width="136" height="44" rx="10" fill="#fff4dc" stroke="#e2c36f" />
  <text x="154" y="248" text-anchor="middle" font-size="17" font-weight="700">请求 C</text>
  <text x="243" y="300" text-anchor="middle" font-size="15" fill="#8b4b4b">问题:请求长度动态变化,显存碎片越来越多</text>

  <g>
    <rect x="568" y="106" width="142" height="164" rx="18" fill="#ffffff" stroke="#b8d8cf" />
    <text x="639" y="130" text-anchor="middle" font-size="17" font-weight="700">逻辑页表</text>
    <text x="639" y="156" text-anchor="middle" font-size="13" fill="#4b5563">A: 3 -> 7 -> 9</text>
    <text x="639" y="182" text-anchor="middle" font-size="13" fill="#4b5563">B: 1 -> 6</text>
    <text x="639" y="208" text-anchor="middle" font-size="13" fill="#4b5563">C: 2 -> 8</text>
    <text x="639" y="242" text-anchor="middle" font-size="12" fill="#4b5563">逻辑顺序与物理位置解耦</text>
  </g>
  <g>
    <rect x="748" y="106" width="150" height="40" rx="10" fill="#e8f1ff" stroke="#98b7e1" />
    <text x="823" y="131" text-anchor="middle" font-size="16" font-weight="700">物理页块 1</text>
    <rect x="748" y="154" width="150" height="40" rx="10" fill="#eef6e8" stroke="#a8c48e" />
    <text x="823" y="179" text-anchor="middle" font-size="16" font-weight="700">物理页块 2</text>
    <rect x="748" y="202" width="150" height="40" rx="10" fill="#fff4dc" stroke="#e2c36f" />
    <text x="823" y="227" text-anchor="middle" font-size="16" font-weight="700">物理页块 3</text>
    <rect x="748" y="250" width="150" height="40" rx="10" fill="#fce7ef" stroke="#e2a8bd" />
    <text x="823" y="275" text-anchor="middle" font-size="16" font-weight="700">更多页块...</text>
  </g>
  <line x1="710" y1="188" x2="748" y2="188" stroke="#5b6b7f" stroke-width="3" marker-end="url(#page-arrow)" />
  <text x="737" y="314" text-anchor="middle" font-size="15" fill="#355c52">收益:近零浪费、更灵活扩容与回收、更适合动态请求</text>
</g>
PagedAttention 的关键不在“缓存会不会存在”,而在“既然缓存不可避免,能不能把它管理得像操作系统分页一样高效”。

为什么“近零浪费”这么关键

论文特别强调 near-zero waste,并不是一个夸张宣传,而是服务系统最实际的痛点之一。对推理系统来说,显存浪费会带来连锁反应:

  • 能并发的请求数下降
  • batch 做不大
  • GPU 利用率下降
  • 单位成本上升

因此,PagedAttention 的意义不是“让某个请求更快一点”,而是让整机吞吐和资源利用率明显改善。这种改进在商业环境里往往比单次 benchmark 提升更有价值。

vLLM 不是只有 PagedAttention

很多人提到 vLLM 时会只记住 PagedAttention,但论文真正重要的是“PagedAttention + serving system”这个整体。

除了分页式缓存管理外,它还强调:

  • 更灵活的请求调度
  • 请求之间的缓存共享
  • 对复杂解码方式的支持
  • 更适合在线服务场景的吞吐设计

也就是说,vLLM 并不是单一算子优化,而是围绕 LLM serving 做了完整系统层设计。

它和连续批处理是什么关系

PagedAttention 和 continuous batching 很容易被混在一起,但它们解决的层级不同:

  • Continuous batching:关注“请求如何动态进出 batch,让 GPU 不要空等”。
  • PagedAttention:关注“KV Cache 如何高效分配和回收,不要把显存浪费掉”。

两者结合后,效果才会真正明显:

  1. 有了连续批处理,系统能更动态地利用计算槽位。
  2. 有了分页式缓存,系统能更动态地利用显存槽位。

一个解决调度效率,一个解决内存效率。vLLM 的强处就在于它们是配套工作的,而不是只优化其中一半。

实验结果说明了什么

论文最重要的实验结论,不是某个绝对 token/s 数字,而是它在相同延迟水平下,相比当时强基线系统显著提升了吞吐,尤其在以下情况下更明显:

  • 请求更长
  • 模型更大
  • 解码策略更复杂

这说明 PagedAttention 的收益并不是“玩具环境里的小修小补”,而是会随着真实服务压力增大变得更有价值。

为什么它对今天的开源生态影响这么大

vLLM 很快成为开源推理服务的关键选项,原因并不神秘:

  1. 问题足够真实,几乎所有团队都会遇到。
  2. 方案足够工程化,容易和服务需求对接。
  3. 收益足够明确,吞吐和资源利用率提升能直接体现在成本上。

这和某些只在单一 benchmark 上表现漂亮、却难以接入生产环境的系统论文很不一样。vLLM 成功的一个重要原因,是它解决的是“大家已经被卡住的问题”。

它和 KV Cache 教程里的内容如何对应

如果你已经读过站内的 KV Cache 与推理性能优化,可以把两者这样对应:

  • 教程讲的是:为什么要缓存,缓存公式怎么估算,prefill / decode 有什么不同。
  • vLLM 论文讲的是:既然缓存已经不可避免,如何把它在服务系统里管好。

因此,KV Cache 教程更偏原理层,vLLM 论文更偏系统层。两者连起来看,才能真正理解为什么线上推理优化是一个完整链路。

局限:PagedAttention 也不是一切问题的终点

虽然它非常重要,但也要看到它不能单独解决所有服务问题:

1. 它不改变模型本身的计算复杂度

PagedAttention 主要优化的是内存管理与吞吐,不是把模型计算本体变轻。

2. 服务系统仍然要面对调度、公平性和多租户问题

显存利用率提高了,不等于所有 SLA、优先级和隔离问题自动消失。

3. 不同硬件和部署环境的收益会有差异

系统论文的效果从来都依赖环境,不能机械地把某个倍数复制到任何场景。

4. 更复杂的解码策略和工具调用链还会引入新瓶颈

缓存管理只是 serving stack 的一个关键环节,而不是全部。

因此,PagedAttention 是推理系统中的关键地基,但不是完整大楼。

从今天看,这篇论文真正改变了什么

它最重要的贡献,也许不是“提出了一个 clever 的内存技巧”,而是把 LLM serving 的关注点正式推向了:

  • 内存碎片
  • 请求动态性
  • 显存利用率
  • 吞吐与延迟联合优化

也就是说,它让大家更清楚地意识到:LLM 服务不是把模型塞进 GPU 就结束,而是一门接近操作系统和数据库调度风格的系统工程。

读这篇论文时最该抓住什么

如果你只想记住三点,请记住:

  1. LLM serving 的核心瓶颈之一是动态 KV Cache 管理。
  2. PagedAttention 借用了分页思想,把逻辑序列与物理内存解耦。
  3. vLLM 的价值在于它把缓存管理、调度和服务吞吐放进了同一个系统框架里。

把这三点想清楚,你再去看推理框架选型、batch 策略、显存优化时,就会更有抓手。

延伸阅读

相关内容

沿着相近主题继续阅读,加深对方法边界与实践场景的理解。