DingoCache 把 KV Cache 从单个推理实例扩展到共享存储:多个节点的 NVMe 组成分布式缓存池,由引擎连接器负责保存与恢复推理状态,为长上下文和多轮交互减少重复 Prefill。
概述
一份报告,先总结,再分析风险,最后提取行动项。问题在变,材料没变——每次都重新处理整份报告,用户付出的不只是等待时间,还有重复的计算成本。
长上下文、多轮对话与Agent任务同理:请求之间包含大量相同输入,但一旦被调度到其他实例,或本地KV Cache因容量限制被淘汰,已完成的计算就失效,只能重新执行Prefill。
DingoCache是九章云极DataCanvas开源的分布式KV Cache系统(项目与工具名dfkv),把原本局限于单个实例的KV Cache,用多节点NVMe组成的共享缓存池扩展为跨实例可复用的计算状态。其核心不在于延长KV Cache的保存时间,而在于让已完成的Prefill继续被后续请求使用。
对于前缀稳定、重复处理较多的负载,这意味着:
- 长上下文:复用文档、知识库等公共前缀,减少重复Prefill。
- 多轮Agent:复用系统提示、工具定义与历史上下文。
- 多实例服务:切换实例后,仍可尝试恢复兼容的计算状态。
- 存量硬件复用:用GPU服务器上的已有NVMe构建缓存池,减少新增专用存储设备。
提示
但它并不是业务数据存储,也不能保证所有缓存命中都带来加速。节点变化、布局不兼容、缓存恢复成本以及网络条件,都可能影响最终收益。
共享KV Cache解决什么问题
模型处理输入的阶段称为Prefill。Prefill过程中,模型会生成供后续计算使用的Key/Value状态,即KV Cache。如果后续请求包含相同的前缀,并且对应的模型、精度、并行方式和缓存布局兼容,就可以恢复已有KV Cache,从而跳过相应部分的重复计算。
缓存的不是最终答案,而是已经完成的一部分计算状态。这一区别很重要,因为:同一份材料可以继续回答不同问题,因此共享KV Cache并不要求后续请求完全相同。例如:
- 长文档与知识问答:文档内容保持不变,只在末尾追加不同问题,可以复用文档对应的KV。
- 多轮Agent:稳定的系统提示、工具定义和任务历史可以继续复用。
- 多实例推理:请求被调度到不同实例后,可以尝试从共享缓存池恢复兼容状态。
传统前缀缓存通常位于推理实例本地。它的优势是访问路径短,但缓存生命周期和容量也受到单个实例的显存、主机内存和实例生命周期限制。DingoCache做的是另一层扩展:近端缓存负责更快访问,共享缓存负责扩大可保存、可复用的范围。
因此,DingoCache并不替代显存和主机内存中的本地缓存,而是作为共享缓存层,为跨实例复用提供存储空间。
适合场景
DingoCache更适合前缀稳定、重复处理较多、单次Prefill成本较高的推理负载,典型场景包括:
| 场景 | 可复用内容 | 复用价值 |
|---|---|---|
| 长文档问答 | 文档前缀 | 减少重复Prefill |
| 多轮对话 | 稳定历史上下文 | 降低后续请求计算量 |
| Agent | 系统提示、工具定义、任务历史 | 减少重复上下文处理 |
| 多实例服务 | 已完成的公共前缀 | 降低实例切换带来的缓存损失 |
| 高并发相似请求 | 公共上下文 | 提高已有计算的利用率 |
反过来,如果请求之间几乎没有稳定前缀,或者缓存恢复和数据传输本身已经接近甚至超过重新计算的成本,共享缓存的收益就会降低。因此,“能够缓存”与“缓存值得使用” 是两个不同的问题。
面向推理,也面向实际投入
DingoCache的设计并不只针对一次KV读取的性能,而是围绕推理缓存的生命周期展开。
Apache 2.0开源
DingoCache采用Apache 2.0许可。源码开放,企业可以按照许可条款进行使用、修改和再分发,并可根据自身环境进行部署和定制。
开源版本无需支付软件许可费,但实际部署仍需要承担服务器、网络、存储和运维成本。
原生RDMA数据通路
KV数据面支持原生RDMA,用于降低客户端与缓存节点之间的数据传输开销。
在硬件、驱动和连接器条件满足时,还可以使用GPUDirect RDMA,使KV数据更直接地返回GPU侧,进一步减少数据搬运路径。
围绕KV Cache设计
DingoCache围绕前缀复用、模型布局、并行分片和大对象读写进行设计,并提供SGLang HiCache、vLLM和LMCache适配路径。
存储层负责保存对象,连接器负责理解推理引擎的KV布局,并将恢复的数据转换为引擎可以继续使用的状态。
复用已有NVMe
GPU服务器上的可用NVMe容量可以参与构建共享缓存池。
当已有服务器、SSD、内存和网络满足要求时,可以利用现有资源承担缓存存储,减少额外采购专用缓存设备的需求。
DingoCache可以从软件许可、存储资源和重复计算三个方向降低新增投入,但开源并不意味着零成本。实际收益仍取决于硬件余量、网络条件、SSD使用情况、缓存命中率以及业务负载。
架构:数据直达节点,成员独立管理
DingoCache将推理适配、数据存储和成员管理分开。
- 连接器理解推理引擎的KV布局,并负责KV状态与缓存系统之间的转换。
- 客户端根据对象信息计算目标节点,并组织批量读写。
- 缓存节点负责本地NVMe以及可选RAM热层。
- MDS与etcd负责成员发现、节点注册、租约等控制面能力。
其中一个重要设计是:KV大数据不经过MDS中转,而是由客户端直接访问缓存节点。
客户端利用一致性哈希计算对象目标节点,再发起批量读写请求。这样可以将大数据传输从成员管理路径中分离出来,避免中心节点成为KV数据面的必经路径。缓存服务既可以与推理服务混部,也可以独立部署。推理实例发生重建时,不要求缓存池同步重建。
DingoCache将KV Cache定位为可重新计算的缓存数据,而不是需要永久保存的业务数据,因此不为每个缓存对象维护业务级冗余副本,以减少存储空间、数据复制和一致性维护带来的开销。当缓存对象因节点故障或淘汰等原因丢失时,可以通过重新Prefill生成KV Cache,但这会造成缓存未命中和额外计算,因此DingoCache适合作为推理缓存使用,不应作为业务数据的唯一存储。
跨实例复用,首先要解决“能不能用”
把KV Cache从本地显存移动到共享存储,并不意味着任何KV都可以被任何实例恢复。同一段输入在不同模型版本、缓存精度、并行配置或布局下,可能产生不同的KV状态。 因此,仅仅判断:对象存在、前缀长度相同、Key相同,都不足以证明这个KV可以被另一个推理实例直接使用。
DingoCache通过连接器构造稳定的对象身份。命名空间描述模型和缓存布局的兼容范围,对象键则标识具体的前缀块、缓存组件和并行分片。不同实例的GPU地址可以不同,但模型版本、KV Cache布局、缓存精度、并行方式以及对象的前缀块和分片关系需要保持兼容。也就是说,跨实例共享的关键不是“找到一个KV”,而是“找到一个当前实例能够正确恢复和使用的KV”。
目前DingoCache已提供SGLang HiCache、vLLM直连和LMCache适配路径。不同连接器负责处理各推理框架的KV布局和接口差异,共享底层的缓存存储、对象路由和数据传输能力。需要注意的是,支持多个推理引擎并不意味着缓存可以在不同引擎之间直接互读,实际能否共享仍取决于模型版本、缓存布局、并行配置以及连接器等兼容条件。
存储组织:面向KV对象,而不是单个文件
如果每个KV对象都对应一个独立文件,随着缓存对象数量增加,文件系统元数据和文件操作可能成为额外开销。DingoCache默认使用Slab后端,它会预先分配存储空间,并根据对象大小将空间划分为不同槽位。索引记录对象所在位置和长度,从而避免大量小文件操作。
这种组织方式使缓存的几个关键操作能够围绕统一布局完成:对象写入、批量读取、空间分配、缓存淘汰、索引恢复、空间回收。对于持续写入和频繁淘汰的缓存系统,这一点比单次GET操作的速度更加重要。
缓存对象并不是写入后就可以随意删除。对象可能仍处于:网络传输中、GPU回载中、推理计算使用中、延迟释放状态等状态,因此,DingoCache通过pin、延迟回收等机制保护在途对象,避免缓存淘汰过程中提前回收仍被使用的空间。
这类机制解决的是一个容易被忽略的问题:缓存系统不仅要知道“哪些对象应该删除”,还要知道“哪些空间现在不能被重新使用”。
高速传输与内存控制
共享KV Cache的另一个成本来自数据搬运。如果KV已经存在缓存节点,却需要经过多次CPU内存拷贝才能回到GPU,存储侧节省的Prefill计算可能会被传输开销抵消。
DingoCache的数据面支持原生RDMA,用于降低客户端与缓存节点之间的数据传输开销。在硬件、驱动和连接器条件满足时,还可以使用GPUDirect RDMA,使数据更直接地进入GPU侧。
这里需要区分两个平面:
- KV数据面:支持RDMA,用于传输KV数据。
- 成员管理与连接协商:仍使用TCP。
DingoCache还支持可选的RAM热层。热点KV可以保存在内存中,从而减少重复读取磁盘的路径。对于冷数据,在条件满足时,也可以直接读取到最终热层槽位,减少中间拷贝,同时,缓存系统需要控制内存使用。
在相应传输路径中,操作级租约和动态读取缓冲可以让部分大对象的临时内存跟随在途操作管理,并纳入进程级预算。因此,一个完整的共享KV Cache系统需要同时考虑:传输效率、内存预算、访问授权、对象回收以及GPU回载。 单纯提高网络带宽,并不能解决全部问题。
实测:单次重放耗时缩短约83.5%
在一组历史专项测试中,使用同一模型处理约百万token的合成长前缀,输出长度固定为8token。测试过程分为两个阶段:
- 首次请求执行冷计算,生成对应KV Cache。
- 随后由另一个本地前缀缓存为空的推理实例,从dfkv读取共享KV,并重放相同输入。
以冷计算请求完成耗时为100,共享KV重放耗时约为16.5。因此,本次测试中:请求完成耗时缩短约83.5%。 两次请求均成功完成,访问记录确认第二次请求发生了共享KV读取。
这组数据说明的是:当长前缀已经完成计算,并且另一个实例可以直接恢复兼容KV时,恢复已有计算可能明显快于重新Prefill。 但它并不能直接推导出所有业务都能获得83.5%的耗时下降。能否加速、能加速多少,取决于命中并复用多少前缀、KV回传计算侧的成本、这笔成本相对重新计算是否划算,以及并发规模与引擎调度的影响。
尤其需要注意:缓存命中不等于一定加速。 如果需要读取的KV很小,或者传输、恢复成本已经接近重新计算成本,那么共享缓存的收益可能并不明显。
因此,生产环境评估时,更应该关注命中率、可复用token数量、Prefill节省量和端到端请求耗时,而不是只看单次缓存读取速度。
从“缓存命中”走向“计算复用”
DingoCache真正要解决的问题,不是再增加一个存储层,而是改变推理系统对已有计算结果的使用方式。
传统路径是:请求进入推理实例,经Prefill产生KV Cache。这份KV属于当前实例,请求一旦被调度到其他实例,本地KV可能就无法继续使用。
共享KV Cache在这条链路之外增加了一条跨实例复用路径:请求先查询共享KV,命中则恢复已有状态、直接继续推理,未命中则执行Prefill并把结果写入共享KV。
这样,已经完成的计算结果就不再只属于某一个推理进程,它可以成为后续请求的一种共享计算资产。
使用前需要关注的几个问题
部署前需要依次确认五件事:业务里是否存在足够稳定、可复用的前缀,否则命中率上不去;缓存节点与GPU之间的带宽和RDMA条件能否支撑KV恢复,否则传输会成为新瓶颈;容量有限时哪些对象值得长期保留;节点故障导致缓存丢失时,业务能否回退到正常Prefill而不影响数据完整性;以及多引擎接入时模型、版本、精度、并行配置和布局是否真正兼容——接入不等于互通。
让已有计算继续发挥作用
DingoCache把引擎状态、分布式存储和高速网络放到了同一条优化链路上:连接器理解状态,客户端组织访问,缓存节点保存对象,RDMA缩短数据路径。
它带来的价值并不只是一次更快的KV读取,而是让已经完成的Prefill计算能够在更多后续请求中继续发挥作用。对于长上下文、多轮Agent和多实例推理等场景,这意味着:
- 已有计算不必因为实例切换而立即失效;
- 已有NVMe可以承担更多缓存容量;
- 已有网络基础设施可以参与KV数据传输;
- 推理资源可以更多地用于处理真正新增的输入。
当然,共享缓存也引入了新的工程约束:缓存命中率、网络带宽、对象兼容性、节点故障和回收机制都会影响最终收益。因此,DingoCache更适合被理解为一层面向推理计算复用的共享基础设施:把已经完成的计算留下来,让后续请求尽可能继续使用。
如果你正在为长上下文或多实例推理评估缓存方案,DingoCache已在GitHub上以Apache 2.0许可开源。源码、文档与完整许可条款都可以直接查阅,也欢迎在真实负载上验证它的实际收益:
最后更新于
