推理加速三板斧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。任何一个想做大模型部署的工程师必须把这三个东西理解到「能讲给别人听」的程度。这一篇我们就来做这件事。读完本文你将能理解 Prefill vs Decode 两阶段的本质差异算清 KV Cache 显存账并知道量化怎么优化理解 PagedAttention 如何让显存利用率从 30% 跃升到 90%理解 Continuous Batching 如何让吞吐量提升 5-10×用 vLLM 跑通一个高性能推理服务并能监控关键指标我们开始。一、为什么推理优化是另一个 90% 的工作1.1 朴素推理 vs 优化推理的差距我们先用一组真实数字震撼一下实验设置Llama-3-70B INT8、单 H100 80G、prompt2K、生成512 token、batch32推理方式单卡吞吐tokens/s相对性能HuggingFace Transformers (朴素)~301×Transformers KV Cache~1204×TGIHF 生产版~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 × (ni) attention 计算密集 显存带宽密集 ~1 次 ~512 次生成 512 token 单次耗时长 单次耗时短关键洞察Prefill 是compute-bound——GPU 算力是瓶颈Decode 是memory-bound——GPU 显存带宽是瓶颈这两个阶段需要的优化完全不同阶段主要瓶颈优化方向Prefill算力Flash Attention、Chunked PrefillDecode带宽KV Cache、量化、Batching生产环境的延迟构成TTFTTime To First Token Prefill 耗时 TPOTTime Per Output Token Decode 单 token 耗时 端到端延迟 TTFT N × TPOTTTFT 和 TPOT 是两个互相独立的优化目标。2.2 KV Cache 显存账再算一次KV Cache 显存公式KV_cache 2 × batch × seq_len × num_layers × num_kv_heads × head_dim × dtype_size以Llama-3-70B80 layers, 8 KV heads with GQA, head_dim128, FP16为例上下文单请求 KV Cache可并发数 (单 H100 80G, 模型占 70G 留 10G 给 KV)4K1.3 GB78K2.6 GB332K10.7 GB0连一个都装不下这就是短上下文 多并发vs长上下文 少并发的根本权衡。2.3 KV Cache 量化KV Cache 已经是显存大户把它量化是最直接的优化。主流方案方案显存节省精度损失支持框架FP16基准1×0%全部FP8 (E5M2 / E4M3)2× 0.5%vLLM, TensorRT-LLMINT82×1-2%vLLM, SGLangINT44×3-5%部分任务掉点明显vLLM 实验生产推荐有 H100 →FP8 KV Cache性能精度兼顾老硬件 →INT8 KV Cache极致显存 → INT4但要测业务效果vLLM 启用 FP8 KV Cachevllm serve Qwen/Qwen3-32B\--kv-cache-dtype fp8\--quantizationfp82.4 Prefix Caching把重复计算省掉很多业务场景的 prompt 有大量重复前缀多轮对话每次新对话都带历史前 N 轮的 KV 是重复的RAG每次请求都有相同的 system prompt 检索文档Few-shot固定的 examples 占了大半 promptCode 助手每次都带整个项目上下文朴素做法每次都重新做 Prefill 计算这些 KV。Prefix Caching 做法把高频前缀的 KV 缓存起来下次直接复用。收益惊人多轮对话场景TTFT 降 50-80%RAG 场景TTFT 降 70-90%极端情况90% prompt 重复TTFT 降 95%vLLM 启用vllm serve... --enable-prefix-cachingOpenAI / Anthropic 早已做这个——所以他们的 prompt cache 价格只有正常价的 10-50%。高级Tree-based Prefix CachingSGLangSGLang 进一步做了RadixAttention——用基数树管理多个 prompt 的前缀树支持任意分叉共享[system prompt] / \ [user A] [user B] | | [response] [response]A/B 用户共享 system prompt 的 KV每个用户自己的对话单独存储——节省显存 加速 prefill。三、第二板斧PagedAttentionPagedAttention 是vLLM 的核心创新2023.6Berkeley目前已经被全行业采纳。它解决了一个所有人都忽视但极其严重的问题——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/s4×模型越大PagedAttention 收益越明显。3.4 进阶Copy-on-WriteCoWPagedAttention 还能做一件更聪明的事——KV Cache 共享。场景beam search、并行 sampling、A/B 测试。多个序列共享相同的 prefix。朴素做法每个序列复制一份 prefix KV。CoW 做法多个序列指向同一份prefix KV 页一旦某个序列要修改某页复制一份再改Copy on Write没有修改的页继续共享效果多采样场景显存省 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 到达 → 等其他请求 → 凑齐 batch32 → 一起跑 → 等最长的结束 → 全部返回这有几个致命问题问题 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。关键改动任意时刻可插入新请求——不需要等任意时刻可移除完成的请求——立即返回每个 iteration生成一个 token作为调度单位举例iter 1: 请求 A 在 batch iter 2: 请求 A 在 batch请求 B 到达B 也加入 iter 3: A, B 都在 iter 4: A 完成了立即返回 AB 继续 iter 5: 只有 B 在 batch请求 C 到达加入 iter 6: B, C 都在 ...效果GPU 利用率从 20-30% 提升到 80%短请求不再被长请求绑架吞吐量提升 5-10×4.3 Continuous Batching 的实现挑战实现这个看似简单的优化工程上其实非常难变长 KV Cache 管理——不同请求不同长度需要 PagedAttention 配合变长 attention mask——每个 iteration 重新计算请求优先级与公平性——长请求会不会饿死预填充与解码混合——新请求要先 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 PrefillContinuous Batching 还有一个进化版——Chunked PrefillvLLM 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-45.2 关键监控指标部署后必须监控的 4 个指标指标含义目标值TTFT(Time To First Token)首 token 延迟 500ms短 promptTPOT(Time Per Output Token)单 token 生成时间 50msThroughput整体吞吐 (tokens/s)越高越好GPU UtilizationGPU 利用率80%vLLM 自带 Prometheus metrics endpointcurlhttp://localhost:8000/metrics|grepvllm关键 metricsvllm: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部署后发现性能不达标按这个顺序排查GPU 利用率低 60%是不是 batch 太小提高--max-num-seqs是不是请求太少看num_requests_waitingTTFT 高prompt 太长 → 启用 chunked prefill没开 prefix caching → 启用TPOT 高显存带宽满了看 GPU 利用率模型太大考虑量化OOMKV Cache 量化fp8/int8减少 max num seqs升级到张量并行长尾恶化开 chunked prefill设置 max tokens 上限5.4 性能对比实测我们用 Qwen3-32B 做对比实验单 H100、prompt1K、output512配置吞吐 (tokens/s)TTFTTPOT纯 transformers251200ms40ms KV Cache951100ms11msvLLM 默认1800600ms28ms (batch 摊薄)vLLM fp8 KV2400550ms22msvLLM 全套优化3200280ms20ms127 倍吞吐差距。这就是推理优化的威力。六、扩展话题与下一篇预告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 上跑得飞快但生产场景长尾、突发、长上下文下表现不一致。所以用真实业务数据做测试监控p99 / p999而不只是平均值测试长时间稳定性运行 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 工程化、大模型部署、后端架构实战的技术专栏。写最一线的踩坑经验做最务实的技术拆解。如果这篇文章对你有启发欢迎点赞、转发、关注。我们下篇见。
推理加速三板斧: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。任何一个想做大模型部署的工程师必须把这三个东西理解到「能讲给别人听」的程度。这一篇我们就来做这件事。读完本文你将能理解 Prefill vs Decode 两阶段的本质差异算清 KV Cache 显存账并知道量化怎么优化理解 PagedAttention 如何让显存利用率从 30% 跃升到 90%理解 Continuous Batching 如何让吞吐量提升 5-10×用 vLLM 跑通一个高性能推理服务并能监控关键指标我们开始。一、为什么推理优化是另一个 90% 的工作1.1 朴素推理 vs 优化推理的差距我们先用一组真实数字震撼一下实验设置Llama-3-70B INT8、单 H100 80G、prompt2K、生成512 token、batch32推理方式单卡吞吐tokens/s相对性能HuggingFace Transformers (朴素)~301×Transformers KV Cache~1204×TGIHF 生产版~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 × (ni) attention 计算密集 显存带宽密集 ~1 次 ~512 次生成 512 token 单次耗时长 单次耗时短关键洞察Prefill 是compute-bound——GPU 算力是瓶颈Decode 是memory-bound——GPU 显存带宽是瓶颈这两个阶段需要的优化完全不同阶段主要瓶颈优化方向Prefill算力Flash Attention、Chunked PrefillDecode带宽KV Cache、量化、Batching生产环境的延迟构成TTFTTime To First Token Prefill 耗时 TPOTTime Per Output Token Decode 单 token 耗时 端到端延迟 TTFT N × TPOTTTFT 和 TPOT 是两个互相独立的优化目标。2.2 KV Cache 显存账再算一次KV Cache 显存公式KV_cache 2 × batch × seq_len × num_layers × num_kv_heads × head_dim × dtype_size以Llama-3-70B80 layers, 8 KV heads with GQA, head_dim128, FP16为例上下文单请求 KV Cache可并发数 (单 H100 80G, 模型占 70G 留 10G 给 KV)4K1.3 GB78K2.6 GB332K10.7 GB0连一个都装不下这就是短上下文 多并发vs长上下文 少并发的根本权衡。2.3 KV Cache 量化KV Cache 已经是显存大户把它量化是最直接的优化。主流方案方案显存节省精度损失支持框架FP16基准1×0%全部FP8 (E5M2 / E4M3)2× 0.5%vLLM, TensorRT-LLMINT82×1-2%vLLM, SGLangINT44×3-5%部分任务掉点明显vLLM 实验生产推荐有 H100 →FP8 KV Cache性能精度兼顾老硬件 →INT8 KV Cache极致显存 → INT4但要测业务效果vLLM 启用 FP8 KV Cachevllm serve Qwen/Qwen3-32B\--kv-cache-dtype fp8\--quantizationfp82.4 Prefix Caching把重复计算省掉很多业务场景的 prompt 有大量重复前缀多轮对话每次新对话都带历史前 N 轮的 KV 是重复的RAG每次请求都有相同的 system prompt 检索文档Few-shot固定的 examples 占了大半 promptCode 助手每次都带整个项目上下文朴素做法每次都重新做 Prefill 计算这些 KV。Prefix Caching 做法把高频前缀的 KV 缓存起来下次直接复用。收益惊人多轮对话场景TTFT 降 50-80%RAG 场景TTFT 降 70-90%极端情况90% prompt 重复TTFT 降 95%vLLM 启用vllm serve... --enable-prefix-cachingOpenAI / Anthropic 早已做这个——所以他们的 prompt cache 价格只有正常价的 10-50%。高级Tree-based Prefix CachingSGLangSGLang 进一步做了RadixAttention——用基数树管理多个 prompt 的前缀树支持任意分叉共享[system prompt] / \ [user A] [user B] | | [response] [response]A/B 用户共享 system prompt 的 KV每个用户自己的对话单独存储——节省显存 加速 prefill。三、第二板斧PagedAttentionPagedAttention 是vLLM 的核心创新2023.6Berkeley目前已经被全行业采纳。它解决了一个所有人都忽视但极其严重的问题——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/s4×模型越大PagedAttention 收益越明显。3.4 进阶Copy-on-WriteCoWPagedAttention 还能做一件更聪明的事——KV Cache 共享。场景beam search、并行 sampling、A/B 测试。多个序列共享相同的 prefix。朴素做法每个序列复制一份 prefix KV。CoW 做法多个序列指向同一份prefix KV 页一旦某个序列要修改某页复制一份再改Copy on Write没有修改的页继续共享效果多采样场景显存省 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 到达 → 等其他请求 → 凑齐 batch32 → 一起跑 → 等最长的结束 → 全部返回这有几个致命问题问题 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。关键改动任意时刻可插入新请求——不需要等任意时刻可移除完成的请求——立即返回每个 iteration生成一个 token作为调度单位举例iter 1: 请求 A 在 batch iter 2: 请求 A 在 batch请求 B 到达B 也加入 iter 3: A, B 都在 iter 4: A 完成了立即返回 AB 继续 iter 5: 只有 B 在 batch请求 C 到达加入 iter 6: B, C 都在 ...效果GPU 利用率从 20-30% 提升到 80%短请求不再被长请求绑架吞吐量提升 5-10×4.3 Continuous Batching 的实现挑战实现这个看似简单的优化工程上其实非常难变长 KV Cache 管理——不同请求不同长度需要 PagedAttention 配合变长 attention mask——每个 iteration 重新计算请求优先级与公平性——长请求会不会饿死预填充与解码混合——新请求要先 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 PrefillContinuous Batching 还有一个进化版——Chunked PrefillvLLM 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-45.2 关键监控指标部署后必须监控的 4 个指标指标含义目标值TTFT(Time To First Token)首 token 延迟 500ms短 promptTPOT(Time Per Output Token)单 token 生成时间 50msThroughput整体吞吐 (tokens/s)越高越好GPU UtilizationGPU 利用率80%vLLM 自带 Prometheus metrics endpointcurlhttp://localhost:8000/metrics|grepvllm关键 metricsvllm: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部署后发现性能不达标按这个顺序排查GPU 利用率低 60%是不是 batch 太小提高--max-num-seqs是不是请求太少看num_requests_waitingTTFT 高prompt 太长 → 启用 chunked prefill没开 prefix caching → 启用TPOT 高显存带宽满了看 GPU 利用率模型太大考虑量化OOMKV Cache 量化fp8/int8减少 max num seqs升级到张量并行长尾恶化开 chunked prefill设置 max tokens 上限5.4 性能对比实测我们用 Qwen3-32B 做对比实验单 H100、prompt1K、output512配置吞吐 (tokens/s)TTFTTPOT纯 transformers251200ms40ms KV Cache951100ms11msvLLM 默认1800600ms28ms (batch 摊薄)vLLM fp8 KV2400550ms22msvLLM 全套优化3200280ms20ms127 倍吞吐差距。这就是推理优化的威力。六、扩展话题与下一篇预告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 上跑得飞快但生产场景长尾、突发、长上下文下表现不一致。所以用真实业务数据做测试监控p99 / p999而不只是平均值测试长时间稳定性运行 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 工程化、大模型部署、后端架构实战的技术专栏。写最一线的踩坑经验做最务实的技术拆解。如果这篇文章对你有启发欢迎点赞、转发、关注。我们下篇见。