重要提示:如需以 Markdown 形式查看本页,请在 URL 后追加 `.md`。 完整文档索引见 llms.txt
跳到主要内容
完整文档索引见 llms.txt。 在任意 URL 后追加 `.md` 即可查看该页面的 Markdown 版本。

KV 缓存卸载

KV 缓存卸载是将注意力中的 key/value 数据从 GPU 内存移动到成本更低的存储层(如 CPU 内存或磁盘)的过程。它在保留无需重新计算即可恢复推理能力的同时,释放 GPU 资源。这有助于通过在性能和内存使用之间取得平衡,更高效地扩展 LLM 工作负载。

为什么 KV 缓存会成为 LLM 推理中的瓶颈?

LLM 高度依赖 KV 缓存来加速推理。该缓存会存储输入序列中每个 token 的注意力 key 和 value,使模型在后续步骤中能够复用它们,而无需重新计算。尽管这节省了大量计算资源并带来了更快的推理速度,但也伴随着高昂的内存成本。

随着上下文窗口增大,KV 缓存大小会随序列长度线性增长。这会很快耗尽可用的 GPU 内存,尤其是在长上下文场景中。由于 GPU 内存有限,KV 缓存常常成为运行需要扩展上下文的应用时的瓶颈。

实际上,并非所有 KV 缓存数据都需要始终保留在 GPU 内存中。在许多真实应用中,用户并不会持续不断地与 LLM 交互。例如,用户可能在输入时暂停,或者离开数小时后再回来。在这种情况下,他们的 KV 缓存仍然驻留在 GPU 内存中,尽管它并未被主动使用。类似地,当多个用户或 agent 在不同时间访问同一段对话、同一份文档或同一个会话时,同一份 KV 缓存可能会在交互之间长时间闲置在 GPU 上(而你显然不希望仅仅为了避免重复计算相同内容,就一直浪费 GPU 资源)。

这会导致内存使用效率低下,因为宝贵的 GPU 内存被不活跃会话占用,而不是用于服务新的请求。随着时间推移,这会限制系统能够支持的并发用户数量,并降低整体吞吐量。

为了解决这些问题,KV 缓存卸载会将不活跃或访问频率较低的缓存数据从 GPU 内存移动到成本更低、容量更大的存储层,例如 CPU RAM、本地 SSD 或远程对象存储。当用户恢复交互,或者另一位用户访问相同内容时,缓存可以按需重新加载回 GPU 内存。这样既能避免高代价的重新计算,又能为活跃工作负载释放 GPU 资源。

如何计算 KV 缓存大小

在执行 KV 缓存卸载时,了解它实际消耗了多少内存会很有帮助。

在基于 Transformer 的 LLM 中,每一层注意力层都需要为输入序列中的每个 token 存储两个向量(一个 key 和一个 value)。每层包含多个注意力头,而且所有头通常具有相同的维度。

要估算 KV 缓存消耗了多少内存,请使用下面的计算器:

KV 缓存内存计算器
计算基于 Transformer 的 LLM 所需的 KV 缓存内存
模型参数
批大小(B)
序列长度(S)
常见取值:1024、2048、4096、8192
层数(L)
Attention Heads(H)
Head 维度(D)
位精度(Q)
KV 缓存大小:0.5 GB
这是保存序列中所有 token 的 key 和 value 向量所需的估算内存。
公式:
KV Cache Size (GB) = 2 × B × S × L × H × D × (Q / 8) / (1024^3)
= 2 × 1 × 1024 × 32 × 32 × 128 × (16 / 8) / (1024^3) = 0.50 GB
说明:
KV 缓存大小会随序列长度线性增长。对于长对话或长文档,这很容易 成为显著的内存瓶颈。

你应该在什么情况下为 LLM 卸载 KV 缓存?

KV 缓存卸载在以下场景中特别有用:

  • 你正在部署具有长上下文窗口的 LLM,而这会使 KV 缓存很快超出 GPU 内存容量。
  • 多个用户或 agent 需要跨会话与相同的底层内容或上下文交互。例如,在集成了 LLM 的 IDE 中工作的开发者,往往会反复与同一段代码片段交互。
  • 你的部署受到内存约束,或者你需要为基础设施成本做优化。
  • 你正在许多分布式 worker 之间扩展推理,而 GPU 资源又比较有限。
  • 你的工作负载中包含间歇性或空闲的用户会话,在这种情况下让 KV 缓存一直留在 GPU 内存中会造成浪费。

KV 缓存卸载的收益

卸载 KV 缓存为扩展和优化 LLM 推理带来了几个重要优势:

  • 更好的资源利用率。 通过将不活跃或共享的 KV 数据移出 GPU 内存,你可以为新请求释放空间。这使得同一张 GPU 能在不触及内存上限的情况下服务更多并发用户或更长的输入序列。
  • 更低的计算成本。 GPU 内存昂贵且有限。卸载让工作负载可以利用更便宜的存储层(例如 CPU RAM 或磁盘),从而减少为了管理缓存而过度配置高端 GPU 的需求。
  • 更低的延迟:卸载让模型在推理过程中可以跳过冗余的 KV 计算,尤其是在多轮交互中存在上下文重叠时。这会显著降低 TTFT 和整体延迟。NVIDIA 报告称,相比从头重新计算 KV 缓存,KV 缓存卸载对于大输入序列可以实现最高 14× 更快的 TTFT

KV 缓存卸载中的权衡

虽然 KV 缓存卸载能够显著提升内存效率和吞吐量,但卸载目标的速度至关重要。如果存储层(例如 CPU RAM 或磁盘)过慢,那么将 KV 数据传回 GPU 的开销可能会抵消其收益,尤其是在对延迟敏感的应用中。

请确保传输数据的成本低于从头重新计算缓存的成本。在长时间、多轮对话中通常是这样,因为复用先前上下文至关重要,而重新计算会非常昂贵。

当系统使用选择性 KV 卸载时,还存在质量方面的权衡。在解码期间,运行时可能需要决定哪些 key 和 value 应该返回 GPU。如果它漏掉了重要的上下文 token,模型可能会生成更差的回答。在多文档 QA、法律审查和代码库推理等上下文密集型工作负载中,这种风险尤其高,因为提示中的许多细节都可能很重要。

这篇论文 突出了这一问题:一些 KV 卸载方法在常见长上下文基准上表现良好,但在需要从提示中检索大量事实的任务上会退化。实践中的经验是,长上下文长度与上下文强度并不是一回事。在生产环境中启用选择性 KV 卸载之前,应当在与你工作负载匹配的任务上,将它与完整注意力基线进行比较。除了 TTFT、TPOT、吞吐量、GPU 内存占用和 host-to-device 传输外,也要同时跟踪回答质量。

使用 LMCache 卸载 KV 缓存

LMCache 是一个 LLM 服务引擎扩展,旨在通过降低 TTFT 并提升吞吐量来优化 LLM 推理,尤其适用于长上下文工作负载。它支持在不同引擎实例之间复用重复输入内容(不仅仅是前缀)的 KV 缓存。

通过将 KV 缓存存储在多层内存中,包括 GPU、CPU DRAM 和本地磁盘,LMCache 显著减少了冗余计算。这改进了响应时间并节省了 GPU 周期,使其非常适合多轮 QA、RAG 和文档级推理等工作负载。

在基准测试中,将 LMCache 与 vLLM 结合后,在多种用例中已实现 3×–10× 的延迟降低。

一些开源项目已经集成了 LMCache,以支持高效的 KV 缓存卸载和复用:

  • llm-d 使用 LMCache 将 KV 缓存数据从 GPU 内存卸载到成本更低、容量更充足的存储层,例如 CPU 内存和网络磁盘。
  • KServe 集成 LMCache,以降低推理成本,并在大规模场景下确保延迟和吞吐量两方面的 SLO。
  • vLLM 使用 LMCache 进行 CPU 卸载、请求之间的缓存共享,以及分离式预填充。这带来了更好的内存管理,并提高了资源效率。

LMCache 目前支持将 KV 缓存数据卸载到多种存储后端,从 CPU 内存和文件系统等本地选项,到 Mooncake 和 ValKey 等分布式系统。