<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>大模型推理 on 辰远</title>
        <link>/tags/%E5%A4%A7%E6%A8%A1%E5%9E%8B%E6%8E%A8%E7%90%86/</link>
        <description>Recent content in 大模型推理 on 辰远</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <copyright>Lee</copyright>
        <lastBuildDate>Sun, 27 Sep 2026 09:08:30 +0800</lastBuildDate><atom:link href="/tags/%E5%A4%A7%E6%A8%A1%E5%9E%8B%E6%8E%A8%E7%90%86/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>PagedAttention：局部更慢，系统为何更快</title>
            <link>/p/vllm-pagedattention/</link>
            <pubDate>Sun, 27 Sep 2026 00:00:00 +0000</pubDate>
            <guid>/p/vllm-pagedattention/</guid>
            <description>&lt;img src=&#34;/p/vllm-pagedattention/cover.jpg&#34; alt=&#34;Featured image of post PagedAttention：局部更慢，系统为何更快&#34; /&gt;&lt;p&gt;PagedAttention 最值得理解的地方，不是“把操作系统分页搬到 GPU”这句类比，而是一个更反直觉的结果：论文测得，它访问块表、处理可变长度后，注意力 kernel 的延迟比高度优化的连续内存实现高 &lt;strong&gt;20%–26%&lt;/strong&gt;；但由它支撑的 vLLM，端到端服务吞吐反而显著更高。&lt;/p&gt;&#xA;&lt;p&gt;局部算子变慢，系统为何变快？因为在线推理的稀缺资源往往不是一次 attention 少了几微秒，而是显存里还能同时容纳多少条正在生长的序列。PagedAttention 接受一次间接寻址的成本，换来更少的 KV cache 浪费、更大的动态 batch，以及前缀之间安全共享内存的能力。它优化的不是一条公式，而是整个服务系统可用的并发度。&lt;/p&gt;&#xA;&lt;h2 id=&#34;kv-cache-不是普通张量而是一批长度未知的活对象&#34;&gt;KV cache 不是普通张量，而是一批长度未知的活对象&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;自回归解码每次只产生一个新 token。旧 token 的 key 和 value 不必重复计算，而是留在显存里供之后的 query 读取，这就是 KV cache。对某个请求，它从 prompt 开始，随后每一步都增长一点；遇到结束符时又整体释放。&lt;/p&gt;&#xA;&lt;p&gt;这类数据有三个麻烦：最终长度未知，不同请求同时到达和离开，而且 decode 每一步都要快速访问此前全部缓存。早期服务系统通常为一条序列预留一块连续区域，大小按允许的最大长度或预测输出长度决定。这样最容易交给常规 tensor kernel，却同时制造三种浪费：尚未生成 token 占着的预留空间、分配块内部的空洞，以及不同大小区域释放后留下的外部碎片。&lt;/p&gt;&#xA;&lt;p&gt;PagedAttention 论文在其基线实验中观察到，连续预留方案真正存放 token 状态的显存只有 &lt;strong&gt;20.4%–38.2%&lt;/strong&gt;。这个数字不是所有部署的固定比例，却清楚揭示了系统问题：即使模型权重不变、单次计算也不变，低效分配仍会把本可进入 batch 的请求挡在显存之外。&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;/p/vllm-pagedattention/memory-waste.svg&#34;&gt;&lt;figcaption&gt;&#xA;&#x9;&#x9;&#x9;&lt;h4&gt;图 1：连续预留按最大长度占位；分页方案只在需要时分配固定大小的 KV 块&lt;/h4&gt;&#xA;&#x9;&#x9;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;h2 id=&#34;页表真正解开的是逻辑连续和物理连续&#34;&gt;页表真正解开的，是“逻辑连续”和“物理连续”&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;PagedAttention 把一条序列的 KV cache 按固定 token 数切成&lt;strong&gt;逻辑块&lt;/strong&gt;。GPU 显存则预先划成同样大小的&lt;strong&gt;物理块&lt;/strong&gt;。请求看到的逻辑块 0、1、2 仍然按 token 顺序连续，但它们可以映射到物理块 7、1、3，彼此完全不相邻；一张 block table 保存这层映射。&lt;/p&gt;&#xA;&lt;p&gt;生成开始时，系统只为 prompt 已经占用的逻辑块分配物理块。最后一块还有空位，新 token 就写进去；填满后，才从空闲池再取一个物理块，并在块表末尾增加映射。因此显存不再按“也许会生成到最大长度”预留，而是随序列真实增长。&lt;/p&gt;&#xA;&lt;p&gt;这种设计没有神奇地消除内部碎片：每条活跃序列的最后一个块仍可能没填满。关键是浪费被限制在&lt;strong&gt;至多一个块&lt;/strong&gt;，不再扩散到整段最大上下文。官方发布文章报告其测试中的实际浪费低于 4%。块也不是越小越好：小块降低尾部浪费，却增加块表项和 kernel 寻址开销；大块更利于并行读取，却提高碎片。原论文的消融实验发现 16-token block 在其工作负载中取得了较好平衡，这是一项测量结果，不是跨模型、硬件都成立的常数。&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;/p/vllm-pagedattention/block-table.svg&#34;&gt;&lt;figcaption&gt;&#xA;&#x9;&#x9;&#x9;&lt;h4&gt;图 2：逻辑 token 顺序保持连续，block table 把它们映射到离散物理块，并按需扩展&lt;/h4&gt;&#xA;&#x9;&#x9;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;注意力计算也必须配合这种布局。kernel 不能再拿一个连续指针扫完整个 KV tensor，而要按块表找到各个 K/V 块，再分块完成 score、softmax 和加权求和。数学上的 attention 没变，变化的是缓存地址的获得方式。这正是那 20%–26% kernel 延迟代价的来源之一：多了间接寻址、分支与可变长度处理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;一块内存如何安全地属于多条序列&#34;&gt;一块内存，如何安全地属于多条序列&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;分页的第二个收益是共享。并行采样、beam search 或多个具有相同 prompt 的请求，会拥有相同的前缀 KV cache。若每条分支都复制完整前缀，显存与带宽会被重复内容吞掉；有了块表，多条逻辑序列可以把前缀项指向同一组物理块。&lt;/p&gt;&#xA;&lt;p&gt;vLLM 为物理块维护引用计数。分支只读共享前缀时，不发生复制；当某个分支需要改写仍被共享的最后一块，系统才执行 copy-on-write：复制这个块、更新该分支的映射，再继续写入。已经填满的旧块保持共享。论文在 beam search 场景中报告最多可节省 55% 的 KV cache 内存，收益来自共享模式本身，不能简单外推到每一种采样配置。&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;/p/vllm-pagedattention/sharing.svg&#34;&gt;&lt;figcaption&gt;&#xA;&#x9;&#x9;&#x9;&lt;h4&gt;图 3：多个分支共享前缀物理块，只在改写共享尾块时触发 copy-on-write&lt;/h4&gt;&#xA;&#x9;&#x9;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;后来 vLLM 的 automatic prefix caching 进一步把“块可共享”变成“块可查找”：完整 KV block 由父块 hash、当前 block token 以及 LoRA、多模态输入、cache salt 等附加信息共同标识。新请求命中相同前缀时，可以复用已有 KV，跳过对应的 prefill 计算。这里要分清两层贡献：PagedAttention 提供块级存储与映射的基础；prefix caching 还需要内容寻址、淘汰和多租户隔离策略。&lt;/p&gt;&#xA;&lt;h2 id=&#34;更大的-batch才是吞吐提升的传动轴&#34;&gt;更大的 batch，才是吞吐提升的传动轴&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;decode 通常受内存带宽限制：每一步只增加一个 token，却要读取模型权重与不断增长的 KV cache。把更多请求放进同一轮执行，可以摊薄权重读取和调度开销，提高 GPU 利用率。但请求长度各异：有人刚进入 prefill，有人已经 decode 数百步，也有人在这一轮结束。&lt;/p&gt;&#xA;&lt;p&gt;iteration-level scheduling（通常称 continuous batching）允许系统在每轮迭代后移除完成请求、加入新请求。PagedAttention 没有发明这种调度方式；它解决的是调度器做出新 batch 后，显存能否随请求加入、增长、分叉和退出而快速重新组合。二者组合后的因果链条是：&lt;/p&gt;&#xA;&#xD;&#xA;    &lt;blockquote&gt;&#xD;&#xA;        &lt;p&gt;按需块分配与共享 → 更少 KV 浪费 → 同时容纳更多序列 → 更大的有效 batch → 更高 GPU 利用率与服务吞吐。&lt;/p&gt;&#xA;&#xD;&#xA;    &lt;/blockquote&gt;&#xD;&#xA;&lt;p&gt;原论文在当时的 OPT、LLaMA 工作负载和 A100/A10G 等实验环境中，相对 FasterTransformer 与论文复现的 Orca 报告了约 &lt;strong&gt;2–4 倍&lt;/strong&gt;吞吐提升；在 ShareGPT 基本采样实验里，vLLM 可承受的请求率相对不可实现的 Orca Oracle 高 1.7–2.7 倍。这里的 Oracle 已提前知道输出长度，因此这个对比尤其说明：动态内存管理能够抵消单个 kernel 的额外成本。&lt;/p&gt;&#xA;&lt;p&gt;不过，这些倍率属于 2023 年的特定模型、硬件、trace 与基线。今天判断一个 serving engine，仍要同时看 time to first token、time per output token、尾延迟、并发、prompt/output 长度分布、量化方式和调度策略。吞吐数字脱离这些条件就没有可移植性。&lt;/p&gt;&#xA;&lt;h2 id=&#34;它和-flashattention-优化的是两张不同的账&#34;&gt;它和 FlashAttention 优化的是两张不同的账&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;两者名字里都有 Attention，也都关心显存，但问题不同。&lt;/p&gt;&#xA;&lt;p&gt;FlashAttention 关注一次 attention 内部怎样搬运数据：用 tiling 和 online softmax 避免把完整 score/probability 矩阵落到 HBM。PagedAttention 关注许多请求的 KV cache 怎样存放：用块表让逻辑连续的序列落在离散物理块里，并支持按需增长和共享。前者主要重排算子内部数据流，后者重构服务系统的数据结构与资源管理。&lt;/p&gt;&#xA;&lt;p&gt;它们可以共存。prefill 阶段常需要高效处理大块 query；decode 阶段则尤其依赖可增长的 KV cache、调度和高效 paged decode kernel。现代 vLLM 也支持多个 attention backend，因此不应把 vLLM 的全部性能等同于论文时代某一个 CUDA kernel。PagedAttention 更长久的影响，是让“KV cache 是一种需要操作系统式管理的动态资源”成为推理系统的基本设计语言。&lt;/p&gt;&#xA;&lt;h2 id=&#34;分页不是免费午餐&#34;&gt;分页不是免费午餐&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;这套方法也有明确边界。&lt;/p&gt;&#xA;&lt;p&gt;首先，块表翻译和非连续访问会增加 kernel 复杂度，访问模式不好时还可能损害局部性；论文的微基准已经诚实展示了这一点。其次，块大小是一项 workload-dependent trade-off，短序列、长上下文、GQA/MLA、混合注意力模型所需的最优布局未必相同。再次，显存容量只是服务瓶颈之一：prefix prefill 的计算、跨 GPU 通信、CPU 前端、采样、排队策略与 SLO 都可能接管瓶颈。&lt;/p&gt;&#xA;&lt;p&gt;最后，分页解决“存在哪里”，不自动解决“哪些缓存值得保留”。prefix cache 命中率、淘汰算法、租户隔离和 cache salt 关系到效率与安全；把不同租户的可复用前缀混在一起，甚至可能形成时序侧信道。因此，块级管理是一层基础设施，而不是完成态的缓存策略。&lt;/p&gt;&#xA;&lt;p&gt;PagedAttention 的价值恰恰在于这种系统视角。它没有减少模型参数，也没有让 attention 的数学复杂度消失；它只是把一块经常被当作“tensor 细节”的 KV cache，重新定义成需要分配、映射、引用计数、写时复制和调度协同的运行时对象。&lt;/p&gt;&#xA;&lt;p&gt;所以，局部 kernel 慢一点而系统更快，并不矛盾。优化目标从“让一次算子最快”换成“让有限显存服务最多有用工作”后，那次额外寻址就不再是纯损失，而是一笔购买并发度的费用。这也是 vLLM / PagedAttention 留给推理系统最重要的设计启示。&lt;/p&gt;&#xA;&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&#xD;&#xA;&lt;/h2&gt;&lt;ol&gt;&#xA;&lt;li&gt;Kwon et al., &lt;a class=&#34;link&#34; href=&#34;https://arxiv.org/abs/2309.06180&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xD;&#xA;    &gt;Efficient Memory Management for Large Language Model Serving with PagedAttention&lt;/a&gt;, SOSP 2023.&lt;/li&gt;&#xA;&lt;li&gt;vLLM Team, &lt;a class=&#34;link&#34; href=&#34;https://vllm.ai/blog/2023-06-20-vllm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xD;&#xA;    &gt;vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention&lt;/a&gt;, 2023.&lt;/li&gt;&#xA;&lt;li&gt;vLLM Project, &lt;a class=&#34;link&#34; href=&#34;https://github.com/vllm-project/vllm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xD;&#xA;    &gt;vLLM official repository&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;vLLM Documentation, &lt;a class=&#34;link&#34; href=&#34;https://docs.vllm.ai/en/latest/design/prefix_caching/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xD;&#xA;    &gt;Automatic Prefix Caching&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;vLLM Team, &lt;a class=&#34;link&#34; href=&#34;https://vllm.ai/blog/2025-09-05-anatomy-of-vllm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xD;&#xA;    &gt;Inside vLLM: Anatomy of a High-Throughput LLM Inference System&lt;/a&gt;, 2025.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;</description>
        </item></channel>
</rss>
