当前位置: 首页 > news >正文

推理加速三板斧:KV Cache、PagedAttention、Continuous Batching

推理加速三板斧:KV Cache、PagedAttention、Continuous Batching

《大模型知识与部署》系列 · No.11 / 35(推理优化篇开篇)
适合人群:AI 工程师、后端开发
阅读时间:约 28 分钟


写在前面

入门认知 5 篇 + 训练与微调 5 篇——前 10 篇我们走完了「模型怎么来」的全过程。

从这一篇开始,我们进入推理优化篇(第 11-15 篇)。这是整个系列里和后端工程师最贴近的部分,也是我个人最想认真讲透的部分。

为什么这么说?

很多团队的真实情况是这样的:

  • 模型训完,丢给后端「请部署上线」
  • 后端pip install transformers,写个 FastAPI,跑起来
  • 发现:单 H100 跑 70B,平均 30 tokens/s,并发 1
  • 老板:「为什么这么慢?vLLM 一个请求能跑 1000 tokens/s 啊!」
  • 后端:「……我也是按官方文档写的」

这 30 倍的性能差距,就藏在 vLLM 等推理框架里的"魔法"中。这些"魔法"不是什么不可言说的黑科技,本质就是三个核心技术:

KV Cache、PagedAttention、Continuous Batching。

任何一个想做大模型部署的工程师,必须把这三个东西理解到「能讲给别人听」的程度。这一篇我们就来做这件事。

读完本文你将能:

  1. 理解 Prefill vs Decode 两阶段的本质差异
  2. 算清 KV Cache 显存账,并知道量化怎么优化
  3. 理解 PagedAttention 如何让显存利用率从 30% 跃升到 90%+
  4. 理解 Continuous Batching 如何让吞吐量提升 5-10×
  5. 用 vLLM 跑通一个高性能推理服务,并能监控关键指标

我们开始。


一、为什么推理优化是另一个 90% 的工作

1.1 朴素推理 vs 优化推理的差距

我们先用一组真实数字震撼一下:

实验设置:Llama-3-70B INT8、单 H100 80G、prompt=2K、生成=512 token、batch=32

推理方式单卡吞吐(tokens/s)相对性能
HuggingFace Transformers (朴素)~30
Transformers + KV Cache~120
TGI(HF 生产版)~60020×
vLLM (默认)~200067×
vLLM + INT8 + FP8 KV Cache~3500117×
TensorRT-LLM (极致优化)~4500150×

150 倍的差距。这意味着什么?

  • 不优化:你需要 150 张 H100 服务 1000 并发用户
  • 优化好:1 张 H100 就够

每月成本差距:$300K vs $2K。这就是为什么推理优化是大模型部署的核心议题。

1.2 推理成本 > 训练成本

一个被反复验证的事实:

模型上线后,推理累积成本会在几个月内超过训练成本。

项目训练成本推理成本(月)多少月超过训练
Llama 3-70B$13M~$1M13 个月
DeepSeek V3$5.6M~$0.6M9 个月
中型客服应用~$200K~$30K6 个月
小型 API 包装$0~$5KN/A

这就是为什么 OpenAI / Anthropic 都把推理优化看作头等技术战略——训练是一次性投入,推理是持续支出。

1.3 推理优化的三大维度

工业上把推理优化拆成三个独立维度:

显存优化 ── 让模型放得下 吞吐优化 ── 让单位时间处理的请求更多 延迟优化 ── 让单个请求更快返回

三者经常冲突——比如增加 batch size 提升吞吐,但会增加单请求延迟。工程师的核心工作就是在三者之间找平衡

本系列推理优化篇 5 篇会系统讲清这一切:

篇号主题核心优化维度
11(本篇)KV Cache / PagedAttention / Continuous Batching吞吐 + 显存
12量化压缩显存
13Flash Attention延迟 + 显存
14投机解码延迟
15长上下文优化显存 + 延迟

我们开始第一板斧。


二、第一板斧:KV Cache

第 2 篇我们讲过 KV Cache 的基础原理。这里我们做工程视角的深度拆解——什么时候用、用多少、怎么压缩、怎么复用。

2.1 Prefill vs Decode:两阶段本质不同

大模型生成的工作流程其实是两个完全不同的阶段:

[Prefill 阶段] [Decode 阶段] 处理整个 prompt 每次生成 1 个 token 计算 n × n attention 计算 1 × (n+i) attention 计算密集 显存带宽密集 ~1 次 ~512 次(生成 512 token) 单次耗时长 单次耗时短

关键洞察

  • Prefill 是compute-bound——GPU 算力是瓶颈
  • Decode 是memory-bound——GPU 显存带宽是瓶颈

这两个阶段需要的优化完全不同:

阶段主要瓶颈优化方向
Prefill算力Flash Attention、Chunked Prefill
Decode带宽KV Cache、量化、Batching

生产环境的延迟构成

TTFT(Time To First Token) = Prefill 耗时 TPOT(Time Per Output Token) = Decode 单 token 耗时 端到端延迟 = TTFT + N × TPOT

TTFT 和 TPOT 是两个互相独立的优化目标。

2.2 KV Cache 显存账(再算一次)

KV Cache 显存公式:

KV_cache = 2 × batch × seq_len × num_layers × num_kv_heads × head_dim × dtype_size

Llama-3-70B(80 layers, 8 KV heads with GQA, head_dim=128, FP16)为例:

上下文单请求 KV Cache可并发数 (单 H100 80G, 模型占 70G 留 10G 给 KV)
4K1.3 GB7
8K2.6 GB3
32K10.7 GB0(连一个都装不下)

这就是短上下文 + 多并发vs长上下文 + 少并发的根本权衡。

2.3 KV Cache 量化

KV Cache 已经是显存大户,把它量化是最直接的优化。

主流方案:

方案显存节省精度损失支持框架
FP16(基准)0%全部
FP8 (E5M2 / E4M3)< 0.5%vLLM, TensorRT-LLM
INT81-2%vLLM, SGLang
INT43-5%(部分任务掉点明显)vLLM 实验

生产推荐

  • 有 H100+ →FP8 KV Cache(性能精度兼顾)
  • 老硬件 →INT8 KV Cache
  • 极致显存 → INT4,但要测业务效果

vLLM 启用 FP8 KV Cache:

vllm serve Qwen/Qwen3-32B\--kv-cache-dtype fp8\--quantizationfp8

2.4 Prefix Caching:把"重复计算"省掉

很多业务场景的 prompt 有大量重复前缀

  • 多轮对话:每次新对话都带历史,前 N 轮的 KV 是重复的
  • RAG:每次请求都有相同的 system prompt + 检索文档
  • Few-shot:固定的 examples 占了大半 prompt
  • Code 助手:每次都带整个项目上下文

朴素做法:每次都重新做 Prefill 计算这些 KV。

Prefix Caching 做法:把高频前缀的 KV 缓存起来,下次直接复用。

收益惊人

  • 多轮对话场景:TTFT 降 50-80%
  • RAG 场景:TTFT 降 70-90%
  • 极端情况(90% prompt 重复):TTFT 降 95%

vLLM 启用:

vllm serve... --enable-prefix-caching

OpenAI / Anthropic 早已做这个——所以他们的 prompt cache 价格只有正常价的 10-50%。

高级:Tree-based Prefix Caching(SGLang)

SGLang 进一步做了RadixAttention——用基数树管理多个 prompt 的前缀树,支持任意分叉共享:

[system prompt] / \ [user A] [user B] | | [response] [response]

A/B 用户共享 system prompt 的 KV,每个用户自己的对话单独存储——节省显存 + 加速 prefill


三、第二板斧:PagedAttention

PagedAttention 是vLLM 的核心创新(2023.6,Berkeley),目前已经被全行业采纳。它解决了一个所有人都忽视但极其严重的问题——KV Cache 显存碎片化

3.1 传统 KV Cache 的「三宗罪」

罪 1:连续分配的浪费

传统 KV Cache 给每个请求预分配最大长度的显存。

假设你支持 32K 上下文,那即使一个请求只用了 1K,也得占 32K 的显存(万一它说话长呢)。

实际利用率:30-50%。

罪 2:碎片化

不同请求长度不同,释放后留下碎片——新请求无法利用。

[已用][已用][已用][空][已用][空][空][已用][空] ↑ ↑ ↑ 小碎片,无法被大请求使用
罪 3:长短请求混合崩溃

短请求和长请求一起来时,短请求结束后留下的空间被长请求占满——后续短请求干等。

时刻 1:[长][短][短][短] ← 短的快结束 时刻 2:[长][空][空][空] ← 短的结束了,留下空 时刻 3:[长][新长][...] ← 新长请求占满了空间 时刻 4:[长][新长] ← 没法接新短请求了!

整体显存利用率:通常只有 30-50%。一张 80G 卡,实际有效利用 24-40G。

3.2 PagedAttention 的思路:借鉴 OS 虚拟内存

操作系统怎么处理类似的"碎片化 + 不知道用多少"问题?

分页(Paging)。

PagedAttention 直接借用了这个思想:

KV Cache 显存 → 切成固定大小的"页"(block) 默认 16 token / 页 每个请求的 KV → 按需申请页 不需要连续 用多少分多少

对比

传统:每请求一块连续大显存 [████████████████][░░░░░░░░░░][████████████████] 占了用不到 小碎片 PagedAttention:所有请求共用一个页池 [█A][█B][█A][█C][░][█B][█A][█C][░][█A][░][█B] ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ 请求 A B A C B A C A 散落但满载

通过一张page table把"虚拟的连续 KV"映射到"物理的离散页"——和 OS 完全一样。

3.3 PagedAttention 的实际收益

PagedAttention 让显存利用率从 30% 跃升到 90%+,直接带来:

  • 单卡可并发请求数提升2-4×
  • 端到端吞吐提升2-4×
  • 长短请求混合也不慌

vLLM 官方论文实测数据:

模型朴素 KV CachePagedAttention提升
LLaMA-13B12 reqs/s28 reqs/s2.3×
LLaMA-33B5 reqs/s16 reqs/s3.2×
LLaMA-65B2 reqs/s8 reqs/s

模型越大,PagedAttention 收益越明显。

3.4 进阶:Copy-on-Write(CoW)

PagedAttention 还能做一件更聪明的事——KV Cache 共享

场景:beam search、并行 sampling、A/B 测试。多个序列共享相同的 prefix。

朴素做法:每个序列复制一份 prefix KV。

CoW 做法

  1. 多个序列指向同一份prefix KV 页
  2. 一旦某个序列要修改某页,复制一份再改(Copy on Write)
  3. 没有修改的页继续共享

效果:多采样场景显存省 50-80%

3.5 PagedAttention 的代价

PagedAttention 不是没代价:

  • 页索引开销:每次 attention 计算需要先查 page table,增加几个 % 的开销
  • CUDA Kernel 复杂度高:需要专门的 paged attention kernel
  • 实现成本:vLLM 团队花了几个月才稳定

但相比 2-4× 的吞吐收益,这点代价几乎可以忽略。

现在主流推理框架都已经"PagedAttention 化":vLLM、SGLang、TensorRT-LLM、TGI 都支持。


四、第三板斧:Continuous Batching

第三板斧解决另一个看似简单但极其重要的问题——多请求怎么 batch

4.1 静态 Batching 的悲剧

静态 Batching(朴素做法)

请求 1 到达 → 等其他请求 → 凑齐 batch=32 → 一起跑 → 等最长的结束 → 全部返回

这有几个致命问题:

问题 1:等待延迟

请求来的间隔不规律。要凑齐 32 个,可能要等几秒。用户体验灾难

问题 2:木桶效应
batch 内 32 个请求,输出长度差异巨大: 请求 1: 输出 50 token → 99% 时间在等 请求 2: 输出 100 token → 95% 时间在等 请求 3: 输出 1000 token → 慢悠悠 ... 请求 32: 输出 5000 token → 大家全部陪它跑完

短请求被长请求"绑架",GPU 利用率惨不忍睹。

问题 3:长尾恶化

业务场景中"长 tail" 很常见。99 percentile 的请求可能 10× 于 median。统计上必然出现极差

结果:静态 batching 实际有效 GPU 利用率~ 20-30%

4.2 Continuous Batching:迭代级调度

Continuous Batching 的核心改动:

不在请求级别 batch,而是在 iteration(每生成一个 token)级别 batch。

关键改动

  1. 任意时刻可插入新请求——不需要等
  2. 任意时刻可移除完成的请求——立即返回
  3. 每个 iteration(生成一个 token)作为调度单位

举例

iter 1: 请求 A 在 batch iter 2: 请求 A 在 batch,请求 B 到达,B 也加入 iter 3: A, B 都在 iter 4: A 完成了!立即返回 A,B 继续 iter 5: 只有 B 在 batch,请求 C 到达加入 iter 6: B, C 都在 ...

效果

  • GPU 利用率从 20-30% 提升到 80%+
  • 短请求不再被长请求绑架
  • 吞吐量提升 5-10×

4.3 Continuous Batching 的实现挑战

实现这个看似简单的优化,工程上其实非常难:

  1. 变长 KV Cache 管理——不同请求不同长度,需要 PagedAttention 配合
  2. 变长 attention mask——每个 iteration 重新计算
  3. 请求优先级与公平性——长请求会不会饿死
  4. 预填充与解码混合——新请求要先 prefill,旧请求在 decode

这就是为什么 PagedAttention + Continuous Batching 必须一起做——分开不好实现。

4.4 PagedAttention + Continuous Batching = vLLM 的魔法

PagedAttention 解决"显存放得下",Continuous Batching 解决"GPU 跑得满"。

两者协同的效果:

  • 单卡能放下的请求数:2-4×
  • 每个请求平均跑得快:2-3×
  • 综合吞吐:5-10×

这也是为什么 vLLM 相对朴素推理能快50-100 倍

4.5 进阶:Chunked Prefill

Continuous Batching 还有一个进化版——Chunked Prefill(vLLM 0.5+ 默认)。

问题:Prefill 很重(O(n²) 计算),如果一个长 prompt 来了,它会独占 GPU,把所有 decode 请求阻塞。

Chunked Prefill 的做法:把长 prompt 切成 chunk(如 512 token),逐 chunk 处理,和 decode 请求混合调度

效果

  • 长 prompt 不再阻塞短请求
  • 整体延迟尾部大幅改善
  • 99% latency 降低 50%+

启用:

vllm serve... --enable-chunked-prefill

五、实战 + 关键指标

5.1 vLLM 完整部署示例

# 部署 Qwen3-32B + 全套优化vllm serve Qwen/Qwen3-32B-Instruct\--max-model-len32768\--tensor-parallel-size2\--gpu-memory-utilization0.9\\--enable-prefix-caching\# KV Cache 复用--enable-chunked-prefill\# 分块 prefill--kv-cache-dtype fp8\# KV Cache 量化\--max-num-batched-tokens8192\--max-num-seqs256\# 最大并发数--swap-space16\# CPU swap 备用\--port8000

关键参数解读

参数作用推荐值
--gpu-memory-utilization显存使用上限0.85-0.95
--enable-prefix-caching开启 prefix 复用强烈推荐
--enable-chunked-prefill长 prompt 不阻塞推荐
--kv-cache-dtypeKV Cache 精度fp8 (H100) / int8
--max-num-seqs最大并发看显存
--max-num-batched-tokens单次 batch 总 token通常 = max_seq_len × 2-4

5.2 关键监控指标

部署后必须监控的 4 个指标:

指标含义目标值
TTFT(Time To First Token)首 token 延迟< 500ms(短 prompt)
TPOT(Time Per Output Token)单 token 生成时间< 50ms
Throughput整体吞吐 (tokens/s)越高越好
GPU UtilizationGPU 利用率80%+

vLLM 自带 Prometheus metrics endpoint:

curlhttp://localhost:8000/metrics|grepvllm

关键 metrics:

vllm:time_to_first_token_seconds_histogram vllm:time_per_output_token_seconds_histogram vllm:request_success_total vllm:num_requests_running vllm:num_requests_waiting vllm:gpu_cache_usage_perc vllm:cpu_cache_usage_perc

接到 Grafana 后能可视化看到效果。

5.3 性能调优 Checklist

部署后发现性能不达标,按这个顺序排查:

  1. GPU 利用率低(< 60%)

    • 是不是 batch 太小?提高--max-num-seqs
    • 是不是请求太少?看num_requests_waiting
  2. TTFT 高

    • prompt 太长 → 启用 chunked prefill
    • 没开 prefix caching → 启用
  3. TPOT 高

    • 显存带宽满了?看 GPU 利用率
    • 模型太大?考虑量化
  4. OOM

    • KV Cache 量化(fp8/int8)
    • 减少 max num seqs
    • 升级到张量并行
  5. 长尾恶化

    • 开 chunked prefill
    • 设置 max tokens 上限

5.4 性能对比实测

我们用 Qwen3-32B 做对比实验(单 H100、prompt=1K、output=512):

配置吞吐 (tokens/s)TTFTTPOT
纯 transformers251200ms40ms
+ KV Cache951100ms11ms
vLLM 默认1800600ms28ms (batch 摊薄)
vLLM + fp8 KV2400550ms22ms
vLLM + 全套优化3200280ms20ms

127 倍吞吐差距。这就是推理优化的威力。


六、扩展话题与下一篇预告

6.1 三板斧之外的优化

除了这三板斧,2024-2025 还有几个新进展:

技术解决问题状态
Speculative Decoding串行解码慢主流(第 14 篇)
Tensor Parallel + Pipeline Parallel单卡装不下主流(第 20 篇)
Multi-LoRA Serving多业务复用主流
Disaggregated Prefill/Decode资源利用不均新兴
CPU/GPU 卸载极致显存实验

6.2 推理框架横向对比预告

下一篇我们会进入量化,第 17 篇会做完整的推理框架横评:

框架优势适合
vLLM易用、社区好通用首选
SGLang复杂控制流、JSONAgent / 结构化
TensorRT-LLM极致性能生产追求极限
TGIHF 生态融合HF 用户

6.3 不要只看 benchmark

最后一个反直觉的提醒

性能基准很重要,但不要只盯着 benchmark。

很多框架在标准 benchmark 上跑得飞快,但生产场景(长尾、突发、长上下文)下表现不一致。所以:

  1. 真实业务数据做测试
  2. 监控p99 / p999而不只是平均值
  3. 测试长时间稳定性(运行 24 小时看看)

结语:理解三板斧,理解大模型推理

读完本文你应该明白:

  • KV Cache:解决重复计算,4-10× 加速。Prefill 与 Decode 是两个完全不同的阶段
  • PagedAttention:解决显存碎片,2-4× 提升并发能力。借鉴 OS 虚拟内存的智慧
  • Continuous Batching:解决静态 batch 的悲剧,5-10× 吞吐提升
  • 三者协同= vLLM 的"魔法",相比朴素推理 50-150× 加速
  • 真正的生产部署还要看TTFT/TPOT/Throughput/GPU 利用率四大指标
  • Chunked Prefill / Prefix Caching / KV Cache 量化是当下推荐的进阶配置

下一篇我们继续推理优化:

  • 第 12 篇:量化压缩实战 - INT8 / INT4 / AWQ / GPTQ 全面对比—— 量化是另一个维度的优化,能让 70B 模型从 8 张卡降到 1 张卡。我们会讲清各种量化方法的原理、精度损失、实战配置。

之后是 Flash Attention(第 13 篇)、投机解码(第 14 篇)、长上下文(第 15 篇)。推理优化篇 5 篇连成完整路径——这是大模型工程师真正的"造血能力"。

我们下篇见。


📮关于「码海寻道」
这里是一个聚焦 AI 工程化、大模型部署、后端架构实战的技术专栏。
写最一线的踩坑经验,做最务实的技术拆解。

如果这篇文章对你有启发,欢迎点赞、转发、关注。我们下篇见。

http://www.gsyq.cn/news/1487513.html

相关文章:

  • 人才盘点到底怎么做?别再只会画九宫格了
  • 广东区域建筑木方厂家品质与服务评测对比 - 奔跑123
  • tchMaterial-parser:一键获取国家中小学智慧教育平台电子课本的终极指南
  • Windows终极优化神器:WinUtil完全指南 - 一键搞定所有Windows管理难题
  • FanControl终极指南:3分钟搞定Windows风扇智能控制
  • 2026年6月锯切设备实力厂家推荐分析,锯条/冷切/金属切割/二手圆锯机/锯切设备/锯床配件,锯切设备企业哪个好 - 品牌推荐师
  • 高管流失、战略变形、执行走样:如何靠“组织能力铁三角”让企业重回增长快车道?
  • 嵌入式Bootloader实战:MMC2107二级架构设计与Flash编程器实现
  • Aria2一键安装管理脚本终极指南:高效部署与故障排查完整方案
  • Open3D点云处理避坑指南:边界框、凸包、隐点移除的实战陷阱与优化
  • 3分钟解决!Switch手柄连接PC完整指南:BetterJoy终极教程
  • 解密XAPK到APK转换:零依赖Python工具深度实战指南
  • 虚拟内存:硬盘假装自己是内存
  • AI编程技巧-什么时候改切新会话
  • 潍坊潍城区黄金回收哪家靠谱?2026正规上门回收价格表 - 行行星
  • 终极解决方案:让Windows资源管理器完美显示iPhone HEIC照片缩略图
  • Everpure(P)FY2027 Q1財報
  • CyberdropBunkrDownloader:告别手动下载,3分钟掌握批量下载神器
  • @prosodyai/mcp-docs MCP 服务说明文档
  • 大模型+机器人:VLA(Vision-Language-Action)范式解析
  • 64 Mbit高速串行接口QSPI sram芯片
  • IDM永久激活实用技巧:5步轻松实现下载加速神器免费使用
  • Audacity音频编辑完全指南:从零开始掌握专业级音频处理
  • 保姆级教程:惠普M451/CP1215等老款激光打印机‘搓纸轮更换模式’进入与使用全攻略(附视频)
  • Agent 自进化:核心问题与解决方案
  • 本地人青睐的杭州点心,地道风味值得一试 - 玖叁鹿
  • 终极指南:如何在Linux上完美管理罗技设备 - Solaar完全配置教程
  • 终极开源英雄联盟回放导演工具:专业视频创作与战术分析完整指南
  • 如何解决下载链接失效:Balena Etcher Windows便携版修复指南
  • AsrTools:免费开源智能语音转文字工具完整指南