@KVCache_AI: Mooncake现在支持KV缓存的SSD卸载。随着智能体工作负载成为常态,KV缓存的生存时间正在…
摘要
Mooncake宣布支持KV缓存的SSD卸载,能够经济高效地将KV缓存容量扩展到DRAM之外,适用于长时间运行的智能体工作负载。分析显示,双峰复用模式使得分层存储更加高效。
查看缓存全文
缓存时间: 2026/07/15 15:57
Mooncake 现已支持 KV Cache 的 SSD 卸载。
随着代理型工作负载成为常态,KV 缓存的生命周期变得越来越长,但将所有内容保存在 DRAM 中根本无法扩展。
借助 Mooncake 的分布式 SSD 层级,您可以:
- 将 KV 缓存容量扩展到远超内存的限制。
- 保留长尾 KV 缓存,而不是将其逐出。
- 提高 KV 缓存命中率。即使是微小的提升,也会非线性地转化为显著的预填充加速。
了解更多:https://kvcache.ai/blog/scaling-kv-cache-beyond-memory/…
#LLM #Inference #KVCache #AIInfrastructure #Mooncake
借助 Mooncake SSD 卸载,将 KV 缓存扩展到内存之外
来源:https://kvcache.ai/blog/scaling-kv-cache-beyond-memory/
SSD 卸载变得必要、实用且有利可图
代理型工作负载的兴起从根本上改变了 KV 缓存的角色。编程助手、多轮推理和使用工具的代理会重复使用较长的上下文前缀,同时每次交互仅追加少量新 token。工具调用很容易跨越数十甚至数百轮,将上下文长度推至数十万个 token。这既创造了巨大的机遇,也带来了严峻的挑战:当 KV 缓存被有效保留时,缓存命中率可超过 95%;但一旦发生缓存未命中,系统可能需要重新计算数十万个 token,产生巨大的预填充开销。
然而,KV 缓存的生命周期差异巨大;有些会在数小时甚至更长时间后被重新使用。因此,将所有 KV 缓存保留在昂贵的 HBM 或 DRAM 中既低效又在经济上不可持续。为了量化这一点,我们分析了来自 Qwen-Bailian (https://github.com/alibaba-edu/qwen-bailian-usagetraces-anon) 的生产追踪数据。该数据集包含来自阿里云百炼上一个 Qwen 模型服务集群的两小时采样匿名 KV 缓存追踪。在我们的分析中,我们选择了两个具有代表性的追踪:推理密集型聊天(思考)和代码生成(编码器)。
编码和推理追踪中 KV 块重用的时间局部性和生命周期分布
如图所示,KV 块重用表现出显著的时间局部性极化,而块生命周期跨越多个数量级。在编码场景中,69.2% 的重用块在十分钟内被重新访问,而超过 30 分钟后的冷重用仅占 10.3%。在推理场景中,这种偏斜更为极端:83.0% 的重用块表现出短周期重用,而只有 5.0% 属于冷重用类别。这些分布表明 KV 缓存访问并非遵循简单的单调衰减。相反,它形成了一种双峰模式,其中热集群与冷尾共存。因此,LRU 或固定 TTL 策略可能过早地逐出虽冷但仍有价值的 KV 块,导致灾难性的缓存未命中以及后续的大量预填充重新计算。
这自然引出一个问题:我们能否使用更便宜、更具成本效益的 SSD 来存储这些长尾 KV 块?在我们之前的博客文章《LLM 服务需要多少 KV 缓存预算?》(https://kvcache.ai/blog/calculate-kvcache-cache-budge/) 中,我们通过对代理型工作负载的定量分析回答了这个问题。我们表明,配置额外 DRAM 容量的边际收益迅速减少,使得分层存储架构越来越有吸引力。更重要的是,由于绝大多数的 KV 缓存命中已经可以由相对较小的 DRAM 缓存提供服务,只有极小部分请求需要访问 SSD 层级。换句话说,SSD 可以大幅扩展 KV 缓存容量,同时对读取路径施加的压力非常小。
更吸引人的是,KV 缓存命中率会非线性地转化为预填充加速:如果命中率为 ( r ),则只有 ( 1-r ) 的预填充计算需要重新计算,产生理想的加速比为 ( \frac{1}{1-r} )。由于代理型工作负载通常运行在高命中率区间,即使是长尾 KV 缓存命中率的微小提升,也能转化为预填充性能的极大提升。
Mooncake 解决方案:用于 KV 缓存的分布式 SSD 池
基于这一观察,我们直接在 Mooncake Store 中构建了 SSD 卸载支持。如下图所示,Mooncake 将各个服务节点上的本地 SSD 组织成一个分布式 KV 缓存池,就像它已经对 DRAM 所做的那样。DRAM 仍然是热数据的低延迟服务层级,而更大、成本更低的 SSD 层级则延长了 KV 缓存的生命周期。一个主节点协调两个层级的所有副本的全局元数据,允许任何计算节点透明地发现并重用存储在另一个节点本地 SSD 上的 KV 块。
Mooncake Store 架构,包含 DRAM 和 SSD 分层 KV 缓存池
数据流
Mooncake 使 SSD 访问不处于应用程序的关键写入路径上,并在 DRAM 和 SSD 层级之间异步移动数据。完整流程包括四个操作:将 KV 块卸载到 SSD、按需加载、将频繁重用的块提升回 DRAM,以及在重启后恢复 SSD 元数据。
卸载: SSD 卸载完全异步,绝不会阻塞应用程序的写入路径。新生成的 KV 缓存首先存储在 DRAM 中,并立即可用于服务。后台心跳消息定期与主节点同步,主节点根据配置的策略决定哪些对象应该被卸载。然后本地节点将选定的 KV 块批量处理并刷新到其本地 SSD。Mooncake 目前支持两种卸载策略:主动卸载,它在后台持续刷新新创建的 KV 缓存;基于水印的驱逐,它仅在 DRAM 利用率超过可配置阈值时才开始卸载。
加载与提升: 当请求的 KV 块不再存在于 DRAM 中时,请求者首先向主节点查询其 SSD 副本的位置。目标节点从本地 SSD 读取数据到临时 DRAM 缓冲区,然后请求者通过 RDMA 或 TCP 直接拉取数据。为了避免重复支付 SSD 访问延迟,主节点持续跟踪 SSD 上驻留对象的访问模式。频繁访问的 KV 块会被主动提升回 DRAM,从而允许后续请求完全从内存层级得到服务。
元数据恢复: SSD 上驻留的 KV 块在存储服务或主节点重启后仍然持久存在,但在块可以重用之前,必须将其位置恢复到主节点。Mooncake 将此恢复过程委托给各个存储节点。当一个节点启动时,它会扫描本地的磁盘元数据,并将每个有效对象重新注册到主节点,从而使恢复的 SSD 副本再次全局可发现。
优化 SSD 数据路径
仅仅添加 SSD 层级是不够的。存储堆栈本身必须在 LLM 服务的高度并发访问模式下维持高吞吐量。因此,Mooncake 优化了整个 SSD 数据路径,以最小化软件开销并确保现代 NVMe 设备得到充分利用。
当启用 MOONCAKE_OFFLOAD_USE_URING 时,Mooncake 从 POSIX I/O 切换到基于 io_uring 的实现。与共享全局 ring 不同,每个线程拥有一个私有的 io_uring 实例,从而消除了锁竞争,并允许 I/O 随并发性扩展。
这种每线程的设计还支持将多个读取请求批处理到单个提交中,从而增加队列深度并更好地利用 NVMe 并行性。此外,暂存缓冲区被注册为 io_uring 的固定缓冲区,避免了每次 I/O 时重复注册缓冲区。
在 io_uring 路径中,可以选择启用 O_DIRECT 以绕过页面缓存。Mooncake 透明地使用临时对齐缓冲区处理未对齐的请求,因此用户无需自行管理 4 KB 对齐。
可插拔的存储后端
存储后端定义了对象在磁盘上的组织方式,包括其布局、索引、分配和驱逐策略。由于不同工作负载权衡不同的优先级,如吞吐量和驱逐粒度,Mooncake Store 提供了一个可插拔的后端接口,并内置了三种实现:
- BucketStorageBackend(默认) 将对象分组到桶中,然后刷新到磁盘。每个桶由一个数据文件和一个元数据索引组成,一旦桶达到大小或键的阈值,就写入一次。固定大小的槽确保顺序读写,从而提供更高的 SSD 吞吐量。目前支持桶级别的 FIFO 和 LRU 驱逐策略。
- OffsetAllocatorStorageBackend 将所有对象存储在一个预分配的文件中。与 Mooncake 的 DRAM 存储类似,它使用 OffsetAllocator 来管理空间,支持对象级别的分配和驱逐。
- FilePerKeyBackend(演示) 将每个对象作为单独的文件存储在一个两级哈希分片目录树下。虽然并非为性能而设计,但对于调试和检查磁盘上的数据很有用。
基准测试结果
我们在一个配备 8× A100-SXM4-40GB GPU 和双 RDMA 网卡的单台 DGX 节点上评估端到端性能。评估比较了四种配置:
- 仅 GPU: KV 缓存仅存储在 GPU 内存中。
- HiCache L1 + L2: KV 缓存在设备内存和主机内存之间分布。
- HiCache L1 + L2 + Mooncake: KV 缓存在设备内存、主机内存和 Mooncake DRAM 之间分布。
- HiCache L1 + L2 + Mooncake SSD: KV 缓存在设备内存、主机内存以及 Mooncake DRAM 和 SSD 之间分布。
端到端 TTFT 和预填充吞吐量对比(仅 GPU、HiCache、Mooncake DRAM、SSD)
如上图所示,SSD 卸载显著降低了 TTFT,同时提高了预填充吞吐量。
有/无 Mooncake SSD 卸载时每轮 TTFT 和 KV 缓存命中率
为了理解这些收益的来源,我们按对话轮次分解了 TTFT 和 KV 缓存命中率,输出长度固定为一个 token 以隔离预填充延迟。在前六轮中,内存池对两种配置都足够,它们的命中率都达到 80% 以上。区别在内存耗尽后出现。从第七轮开始,没有 SSD 的 Mooncake 必须逐出 KV 缓存,导致命中率从 83% 骤降至 36%,TTFT 从 6 秒增加到 16 秒。借助 SSD 卸载,被逐出的 KV 块仍然在 NVMe 上可用,使得命中率在第八轮保持在 84% 以上,TTFT 限制在 9.4 秒。
正在进行的工作
Mooncake 的 SSD 卸载支持只是迈向完全分层的 KV 缓存架构的第一步。我们正在积极探索三个主要扩展:
GPU Direct Storage (GDS)。 目前,SSD 卸载在 KV 缓存在 SSD 和 GPU 内存之间移动时仍会通过 DRAM 暂存数据。GDS 去除了这个中间跳转,使得 KV 缓存能够直接在 NVMe SSD 和 GPU HBM 之间传输。这既减少了数据移动开销,也降低了端到端延迟。
分布式存储后端。 虽然本地 NVMe 池化易于部署和操作,但许多用户已经拥有成熟的首选分布式存储系统。为了支持两种模式,Mooncake 正在为分布式存储系统引入一个可插拔的后端接口,并计划首先集成 3FS。
NVMe-oF 集成。 虽然当前的 SSD 层级构建在本地 NVMe 设备之上,但我们也在探索 NVMe over Fabrics (NVMe-oF),以将相同的抽象扩展到远程存储。通过将 NVMe-oF 与 Mooncake 的传输引擎集成,远程 NVMe 设备可以像本地 SSD 一样使用高性能数据路径访问,从而在不牺牲效率的情况下跨机器池化存储资源。
致谢
我们感谢社区中每一位为此工作做出贡献或支持的人。特别感谢:
-
Approaching.AI:Jiahao Lu, Zuoyuan Zhang, Chizheng Fang, Ke Yang
-
蚂蚁集团:Xinjie Zhu, Yongke Zhao, Yue Wan, Tingwei Huang
-
NVIDIA:Mahesh Bapatu
-
阿里云:Xinpeng Zhao, Bo Gao, Xuchun Shang, Teng Ma
-
Mooncake 项目:https://github.com/kvcache-ai/Mooncake
-
文档:https://kvcache-ai.github.io/Mooncake/design/ssd-offload.html
-
使用指南:https://kvcache-ai.github.io/Mooncake/deployment/ssd-offload.html
相似文章
@m_sirovatka: KV Cache 重用是代理工作负载推广中最重要的部分。我们已经将 Mooncake Store 集成到 prime-rl 中,与 vL…
vLLM 集成了 Mooncake Store 用于分布式 KV 缓存重用,支持跨节点前缀缓存,高效服务具有高令牌重用的代理工作负载。
ObjectCache: 用于KV缓存重用的分层对象存储检索
ObjectCache提出使用S3兼容的对象存储来实现LLM KV缓存的重用,以降低成本并增加容量,同时通过协同设计的存储协议和传输调度将延迟开销降至最低。实验表明,对于64K上下文,相比本地DRAM仅增加5.6%的延迟。
MosaicKV:使用动态二维KV缓存压缩服务长上下文LLM
MosaicKV引入了用于长上下文LLM服务的动态二维KV缓存压缩,实现了高达16倍的注意力加速和3倍的内存减少,且精度损失极小。
也许将KV缓存卸载到RAM并不差
一位用户分享了在llama.cpp中将KV缓存卸载到RAM的经验,在释放显存以便运行更大模型和上下文窗口的同时,实现了相近的速度,表明这种权衡通常是值得的。
@songhan_mit:探索我们在KV缓存压缩方面的持续努力:
来自Song Han的一条推文强调了在KV缓存压缩方面的持续工作,其中介绍了Weian Mao的一篇博客,讨论了论文中常常被忽视的系统级方面。