深言速舟 · 学习站

16 缓存机制

Token 工厂拆解手册:从 GPU、推理服务到合同与现金流第四部分 推理系统约 45 分钟更新于 2026-08-04

16.1 缓存原理

KV 缓存解决的是重复计算问题。模型每生成一个新 token,都要回看之前的全部内容。如果每次从头重算,生成第 1000 个字时要把前 999 个字重新算一遍,总计算量随输出长度平方增长。但前 999 个字的中间结果上一轮已经算过,而且不会再变,把这些结果存下来复用,计算量就从平方降为线性。这个机制叫 KV cache,名字来自注意力机制的三个中间量:Query 每轮都变,Key 和 Value 对已有 token 固定,所以只缓存 K 和 V。核

图 31有缓存与无缓存的计算量差异
无缓存:每生成一字重算全部历史12345678910计算量随输出长度平方增长有缓存:每生成一字只算新增的那一个计算量随输出长度线性增长,代价是显存占用随之线性增长这是一次典型的空间换时间:省下的是算力,付出的是显存。于是显存成了新瓶颈,第 5.2 节的分页管理就是为了把这块显存用干净。长上下文时代,KV 缓存的管理效率直接等于单机能服务多少人。
条形宽度为示意,表示单次生成的计算量,不是严格比例。
不存历史就要每次重算,输出一千字要算五十万次。存下来就只算一千次,代价是吃显存。

这是一笔空间换时间的交易:缓存随层数、历史长度、KV 头数、精度和活跃序列增长,长上下文和高并发会同时放大它。状态管理还影响故障与路由:把请求路由到另一副本,不迁移 KV 就要重新 prefill,迁移则要付网络和一致性成本。于是最短队列未必是最低延迟,它可能把请求送到一个没有相关状态的副本。

16.2 分页管理

PagedAttention 解决的是显存碎片问题,它把操作系统的虚拟内存思想搬进显存。早期做法给每个请求预分配一整块连续显存,按可能的最大长度预留;没人知道用户会生成多长,按最大预留就大量浪费,按平均预留则超长请求会崩,实测中这种方式的显存有效利用率常常只有两到四成。分页的做法是把 KV 缓存切成固定大小的块,按需分配,用映射表记录每个请求用了哪些块,块与块物理上不必相邻;浪费降到一个块以内,有效利用率能推到九成以上。核

图 32连续分配与分页分配的对比
连续预分配请求 A 实用 52 预留 180请求 B 实用 140请求 C 实用 30深色为真实用量,浅色为被预留但闲置的显存有效利用率常在 20% 到 40%分页分配同一批显存被切成等大的块,谁需要谁拿,三种颜色代表三个请求浪费仅限每个请求最后一个未填满的块,有效利用率可达 90% 以上衍生好处:块可以被多个请求共享。共同前缀只存一份,这是 5.3 节前缀复用的基础。衍生代价:多一层地址映射,需要专门的注意力算子读取非连续的块。该机制由 vLLM 项目在 2023 年提出,现已成为主流推理引擎的标准做法。
块大小通常为 16 或 32 个 token,具体值随引擎和模型配置不同。
以前是给每个人包一整间房,现在是按床位分。同样的地方能多住三倍人。

类比的边界要说清:有效的部分是地址映射、按需分配和前缀块共享;失效的部分是 GPU 内核对布局有严格要求,分页不消除 KV 随序列增长,也不保证 prefill、采样和网络同幅提速。vLLM 论文报告的 2 到 4 倍吞吐必须连同其模型、硬件、基线和负载一起引用。

16.3 前缀复用

前缀缓存是编程类流量最大的成本杠杆,也是这门生意最重要的技术差异点之一。AI 编程场景有一个强特征:同一个用户的连续请求,前面几万 token 完全相同,都是那份系统提示加同一份代码库。每次请求都重新 prefill,算力就浪费在重复计算上;前缀缓存把这段共同前缀的 KV 保留下来,下次命中直接跳过。

图 33前缀缓存命中率对有效产能的影响
同一用户的连续三次编程请求系统提示 加 代码库上下文 约 5 万 token本轮提问完全相同本轮提问完全相同本轮提问只算一次命中缓存命中缓存命中率与实际 prefill 计算量的关系命中率 0%全量计算命中率 50%计算量减半命中率 88%仅剩 12%同一批硬件,命中率从 0 提到 88%,prefill 侧有效产能提升约八倍。
仅影响 prefill 阶段。decode 阶段不受前缀缓存影响,整体产能提升幅度小于八倍。
编程流量前面几万字每次都一样。存一次反复用,同样的机器能多接八倍的活儿,这是我们能报低价的原因。

命中率的影响是数量级的。录音里提到的一个业务数据是缓存命中率 88%,录如果成立,意味着 prefill 侧的实际计算量只有名义值的约一成二。这个数字直接决定单机能服务的请求数,因此也直接决定收入,它是所有对外报价里最应该被追问的一个参数。追问的方法:命中只在 token 化后的前缀完全一致时发生,对话模板、系统提示或分词器改动都可能让看似相同的文本失去命中;随机独立提示词测不出收益,复制同一提示词又会测出虚高上界。收益要用真实追踪验证,同时报命中请求比例、命中 token 比例、节省的 prefill 时间、占用字节和热点分布:只报请求命中率会高估短前缀的价值,只报 token 命中率又可能掩盖收益集中在少数租户。

路由会反过来影响命中率:把相似前缀送到同一副本能提高局部性,却可能制造热点。第一个优化带来第二个问题,缓存命中变好后负载均衡可能变差,系统要同时看队列和缓存状态,不能把命中率单独设为最高目标。

16.4 存算分离

KV 缓存太大装不下时,把它挪到显存之外,这就是存算分离。显存最贵、容量最小;CPU 内存便宜十倍、容量大十倍,本地 NVMe 固态盘更便宜。把不活跃的 KV 分层下沉到内存和磁盘,需要时取回,能在有限显存下支撑更长的上下文和更高的缓存命中率。代价是取回时的延迟和互联上的传输流量,所以需要高速传输层做搬运,卸载可能释放显存却降低吞吐,划不划算要按负载实测。

图 34KV 缓存的分层存储
GPU 显存 HBM最快 最贵 约 2.3 TB 每机CPU 内存 DRAM次快 容量大约十倍本地 NVMe慢 容量大 成本低跨机共享池供多机复用同一份前缀下沉取回工程上的关键组件是传输引擎:负责在这几层之间高速搬运 KV 块。开源生态里 Mooncake Transfer Engine 已被 vLLM 与 SGLang 集成为 PD 分离的 KV 连接后端。该组件由清华 MADSys 与 Moonshot 侧主要贡献,是国内团队在这条链上少数被广泛采用的基础件。
分层容量与速度为量级示意。是否值得下沉取决于取回延迟能否被 SLA 容忍。
显存装不下就往内存和硬盘上放,用的时候再搬回来。搬得快不快,决定这套能不能用在线上。

16.5 生命周期

缓存状态的生命周期要能被审计。一条 KV 状态从 prefill 创建,随每个 decode token 追加,在请求完成、取消、超时或被抢占时释放;支持前缀复用时,请求结束后部分块继续留在缓存池,直到被淘汰。容量故障经常不是公式算错,而是生命周期某一步没有发生:取消没有传到引擎、异常请求没有释放、引用计数错误,或热门前缀长期占据物理块。监控至少要区分已分配、已使用、已保留、可淘汰和固定五种状态:一个总的 KV 使用率 80% 说明不了剩余 20% 是否连续可用,也说明不了已占用部分有多少可以淘汰。淘汰策略还会改变租户行为:按最近使用淘汰可能让大体积旧前缀长期占位,按字节收益淘汰又可能让小租户的常用前缀被大客户挤掉,多租户系统要决定缓存是公共资源、按租户配额,还是对命中单独计价。

16.6 共享边界

块级共享建立在 token 序列完全一致的前提上,缓存键必须包含模型、权重版本、分词器、适用参数和前缀 token,否则可能命中错误状态。跨租户共享还要过数据隔离这道门:公共系统提示可以复用,不等于客户私有上下文可以在未授权情况下成为别人的缓存;即使调用者不能直接读 KV,侧信道、错误路由和生命周期也应进入威胁模型。技术上可共享和产品上允许共享是两道门。这个问题在第 33 章的数据合规里还会出现:前缀缓存把用户输入以中间态形式保留在显存或存储中,数据合规评估经常漏掉这一层。

追问88% 命中率是在什么模型、什么长度分布、什么并发下测的;命中率口径是请求还是 token;跨租户的前缀共享有没有隔离设计。

修订记录

日期改了什么为什么谁
2026-08-04按章导入,正文与插图保持原样原稿结构清晰,重写反而损失信息工程