KV Cache 与前缀缓存:从原理到 99.9% 命中率的生产实践

KV Cache 与前缀缓存:从原理到 99.9% 命中率的生产实践

Deng YongJie's blog 2 2026-08-08

KV Cache 与前缀缓存:从原理到 99.9% 命中率的生产实践

大模型推理基础设施实战系列 · 第 1 篇

1. 背景与问题:长上下文时代,prefill 成了最贵的部分

长上下文会显著增加首轮计算和缓存容量需求。以常规全注意力自回归模型为例:

  • Decode 阶段通常每序列每步生成一个新 token,需要访问历史状态。低批量时常受访存限制,也可能受计算、通信或调度限制;稀疏注意力、混合状态与投机解码不能直接套用“每步读取全部历史 KV”。
  • Prefill 阶段计算尚未缓存的输入状态,可分块执行。本文 Kimi-K3 的 H20 配置中,约 48 万 token 冷输入需要数分钟;这不是所有模型或 GPU 的统一速度。

在双机 H20 的受控验收中,同一份约 48 万 token 的文档,首次提问的首 token 延迟(TTFT)高达 421 秒。如果用户第二个问题还要重新算一遍这 48 万 token,交互等待会很长。

这正是 KV Cache 与前缀缓存要解决的问题:在身份、状态和容量条件满足时,复用已算好的前缀,减少重复 prefill。

2. 技术原理:KV Cache 是什么,前缀缓存又是什么

2.1 KV Cache:Decode 的基石

常规因果全注意力的第 t 步需要访问此前各位置的 K/V。KV Cache 保存这些状态,避免重复计算历史 K/V;新 token 追加的是一个位置的状态,只有现有块写满后才需要分配新块。混合或稀疏模型还要按其实现核对状态范围。

KV Cache 工作原理

两个关键推论:

  1. 常规全注意力 KV Cache 占用随序列长度线性增长——512K 上下文意味着要为每条请求预留数十万 token 的 KV 空间,这是显存规划的第一约束(本系列第 4 篇详述);
  2. 前缀命中不能省掉后续生成步骤——缓存命中后,每个新 token 的前向计算一步都少不了,本次主要收益是减少 prefill;后台 I/O、缓存容量和调度仍可能间接改变生成延迟。

2.2 前缀缓存:跨请求复用 KV

前缀缓存(Prefix Caching)进一步把 KV 的生命周期从"单次请求内"扩展到"跨请求":匹配可复用的历史 token 前缀;SGLang 使用 Radix 树,vLLM 使用块哈希等实现;新请求到来时,通过相应索引匹配可复用前缀,命中的块直接复用,只有不匹配的尾部才需要 prefill。

前缀缓存的块匹配

工程上有三个必须理解的细节:

  • 块对齐:KV 按固定块大小管理(在我们测试的某混合架构模型上是 768 token 对齐)。文档尾部不足一块的部分无法跨请求复用,会产生一小段必然的重算——所以 480,158 token 的输入,实测最大复用量是 480,000,而不是 480,158;
  • 精确匹配:前缀匹配是 token 级的精确匹配。系统提示、聊天模板、工具定义的任何变化都会从变化点开始破坏匹配。多轮测试需保留约定的历史消息;遗漏或改写会改变模板化后的前缀,但仍可能命中变化点之前的部分;
  • 缓存身份隔离:持久层应核对模型 revision、权重/KV 精度、并行布局、模板及状态格式。哪些身份自动进入 key 取决于引擎和连接器;不能假定换模型或重启会自动隔离残留缓存。

2.3 主流引擎的实现

引擎 前缀缓存实现 分层能力
SGLang RadixAttention;普通模式默认启用,禁用开关为 --disable-radix-cache GPU → Host → Mooncake Store(L1/L2/L3)
vLLM 块哈希前缀缓存;本次显式配置 --enable-prefix-caching GPU → CPU → 文件系统(KV Offloading 连接器)

下文分别列出 SGLang 与 vLLM 的高复用样例,不能据此声称所有请求都能达到 99.9%。参数依据见 SGLang 官方说明。

3. 配对实测:高前缀复用显著降低 TTFT

以下数据来自两套独立部署的真实测量,均为单请求样本(n=1),用于说明方向与量级,不构成 SLO。

3.1 部署 A:Kimi-K3/SGLang,双副本 TP8×PP4,共 64×RTX 6000D

场景(usage 输入 259,994 token) TTFT 服务端复用 / 重算 总 TPM 输出 TPM TPOT
冷请求(输出 414) 51.31 s 64 / 259,933(<1%) 224,998.15 357.70 43.88 ms
暖请求(输出 437) 0.99 s 259,968 / 29(99.99%) 782,104.91 1,312.36 43.55 ms

SGLang 0.5.21、每组并发上限 2,本组只有一个请求在飞,两次均由同一副本承接。引擎复用+重算为 259,997,与 usage 输入相差 3 token;分属两套计数,不强行改成相同。

3.2 部署 B:Kimi-K3/vLLM 0.31.0,eager+UVA 32 GiB/卡,C1,双机 TP8×PP2,16×H20,512K 窗口

实际输入 缓存状态 GPU 复用 token TTFT 总 TPM 输出 TPM
224,156 未命中 0 180.61 s 63,085.15 45.84
224,156 高命中 223,488(99.70%) 3.61 s 589,720.97 265.60
480,158 未命中 0 421.02 s 63,765.70 21.51
480,158 高命中 480,000(99.97%) 2.76 s 944,780.95 285.22

多轮对话场景(追加事实更新、追问原值与更新值)同样验证通过:两档合计 4 条多轮请求全部正确,TTFT 约 3.5–4.0 秒。

3.3 数据背后的三个要点

第一,TTFT 降了 50~150 倍,但"总 token/s 暴涨"是口径现象。 复用的输入 token 也计入吞吐,而墙钟大幅缩短——GPU 并没有变强,只是几乎没做 prefill。报告吞吐必须同窗列出复用与重算 token,否则会被误读成计算能力。

第二,本次未观察到明确的生成阶段提速。 冷请求 TPOT 43.88 ms,暖请求 43.55 ms:两次相差约 0.75%,且各 n=1。前缀缓存不消除生成前向计算,不能把 TTFT 倍数当作 decode 加速倍数。

第三,命中证据必须来自服务端计数。 验收口径:复用率 = 服务端复用 token ÷ (复用 + 重算),冷 <1%、暖 ≥99%,按 GPU / Host / Store 三层分别核对。usage 缺少 cached_tokens 字段的含义是"未上报",不是 0——此时要用引擎侧计数器取证。

生产看板的同窗证据(历史流量窗口截图,已脱敏):实际前缀命中率 99.8–100%、实际复用 / 重算 token/s、Host 缓存槽(约 3.55 Mi 槽位驻留)与 Store RAM 分配同窗呈现——命中率、复用量、缓存驻留三类数字出自同一窗口,才能互相印证:

前缀命中率与复用证据面板(脱敏截图)

4. 难点与解决:混合状态模型的缓存陷阱

即使是常规 Transformer,也要核对缓存身份、位置及块的完整性,不能只凭文件还在就复用。但混合架构模型(如 KDA + MLA)在 KV 之外还有一层"辅助状态"(linear attention 的 recurrent state)。我们在跨重启缓存恢复验证中踩过坑:

引擎从 SSD 成功读回约 48 万 token 的 KV(8 台机器各有 3.15–3.26 GiB 物理读盘证据,Store 层报告命中 479,872 token),但混合预取检查(_check_hybrid_prefetch_result)发现辅助状态覆盖不完整,整段预取被安全丢弃,请求退回重算。

"宁可重算也不用残缺状态"的设计是对的,但带来三条运维结论:

  • KV 命中 ≠ 有效复用:Store 层命中不代表 prefill 真的省了计算,必须再看"最终复用 token"(第 6 篇展开缓存证据链);
  • 混合模型的跨重启/跨引擎缓存恢复要单独验收,不能照搬纯 Transformer 的结论;
  • 单次恢复成功不等于必然命中:正式入口复核时最终复用 token 比例为 49.99%(4 条请求中 2 条复用旧前缀),部分命中必须单列,不能平均成"暖吞吐"。

另一个需要防范的情形是前缀被动态字段破坏:例如把逐请求变化的时间戳放在系统提示开头,会从变化点起失去匹配。这是机制示例,不作为本项目已定位的事故。固定模板、工具定义与语料有助于建立可比实验。

5. 效果与总结

收益维度 实测效果 边界
长文档首 token 延迟 421 s → 2.76 s(−99.3%) 需 >99% 前缀命中;新文档首次仍需完整 prefill
重复输入成本 重算 259,933 → 29 token 块对齐产生尾部少量重算
单请求总速率 H20 480K 暖请求总 token/s 提升约 14.8 倍 口径含复用输入,不代表算力提升
生成阶段 TPOT 43.88 → 43.55 ms n=1,未证明生成提速;不作“必然完全不变”的断言

实践经验总结为五条:

  1. 重复前缀较多时优先评估前缀缓存,按容量和隔离需求配置;
  2. 命中率以服务端计数为准——cached_tokens 缺失是"未上报",不是 0;
  3. 按块理解复用:本次实现的未满块尾部需要重算,别用输入总长宣称 100% 命中;
  4. 混合状态模型单独验收:KV 命中不等于辅助状态完整;
  5. 前缀稳定性是设计问题:动态时间戳、模板变化都会无声摧毁命中率。

下一篇,我们讨论当 prefill 与 decode 相互干扰时,如何把它们拆成两个资源池:PD 分离实战:Prefill/Decode 拆池、配比拐点与容量规划。

系列目录

  1. KV Cache 与前缀缓存:从原理到 99.9% 命中率的生产实践(本篇)
  2. PD 分离实战:Prefill/Decode 拆池、配比拐点与容量规划
  3. GPU→内存→SSD 三级 KV 缓存:Mooncake 分层实战与跨引擎复用陷阱
  4. Kimi-K3 原始 MXFP4 权重512K 长上下文生产部署:双机 16 卡 TP8×PP2 与 CUDA Graph 调优
  5. 大模型压测方法论:如何让性能数据可信
  6. 推理集群可观测性:64 卡监控体系与缓存证据链
  7. MiniMax-H3视频生成服务化:ComfyUI 多 GPU 编排与长任务生命周期
  8. 掉卡排查实录:RTX 5070 反复 Xid 79,如何排查建立证据链
  9. GPU对调定位法:8 卡 RTX 6000D 掉卡,如何用对调缩小故障范围
  10. CUDA 802 不是 NCCL 网络故障:H20 NVSwitch 物理链路排查实录
  11. DeepSeek-V4.1-Flash 双机 16 卡 H20 部署压测:TP8×DP2 与跨机 EP 的边界

数据声明:本文数据来自受控内部测试环境,测量条件已在文中标注;单样本数据只说明方向。