Mooncake
一句话结论:Mooncake 的关键不是“给 vLLM 外接一个缓存”,而是让计算、KV 容量、传输、排队与 SLO 围绕同一个请求共同做决定。
从长对话的浪费说起
用户和 Kimi 连续对话时,新请求往往包含很长的历史前缀,真正新增的只有末尾几句话。如果每次都把全部历史重新做一遍 Prefill,系统会反复计算已经计算过的内容;如果把历史 KV 全留在 GPU,又会很快耗尽昂贵的显存。
可以把它想象成查阅一份不断追加的档案:普通做法每次从第一页重读;Mooncake 把已经读过的页压成可检索的 KV 小块,新请求先取回最长连续前缀,只阅读新增部分,再把完整上下文交给后续生成。

这幅图表达的是认知隐喻,不是物理部署图。真正困难之处有四个:Prefill 与 Decode 的资源特征不同;KV 比 GPU 显存能容纳的更多;远端命中未必比本地重算更快;超长 Prefill 本身仍可能阻塞首 Token。
系统全景
Mooncake 论文把系统分成三个主要部分:
- Conductor:选择 Prefill/Decode 实例,查询 KV 命中,估算排队和传输成本,并执行 SLO 感知的准入与调度。
- Prefill/Decode 集群:Prefill 负责读完整 Prompt 并生成各层 KV;Decode 读取这些状态,以连续批处理逐 Token 生成。
- Disaggregated KVCache:通过 Mooncake Store 管理键、位置、副本和淘汰,通过 Transfer Engine 在注册内存之间搬运数据。

图:Mooncake 论文 Figure 2 的原始裁切。它证明论文公开的组件划分和主数据路径,不证明 2026 年开源仓库与论文时期 Kimi 生产系统逐模块、逐策略完全相同。来源:FAST’25 论文。
一次典型请求可以概括为:
- Conductor 对完整 Block 的前缀哈希按顺序查询,找到最长连续命中。
- 调度器比较候选 Prefill/Decode 实例的命中、排队、传输、计算与 SLO 风险。
- Prefill 实例取回已有 KV,只计算未命中的后缀。
- 每层新 KV 可以边产生边传给 Decode,避免等全部层完成后再一次性搬运。
- Decode 实例把请求加入连续批处理,生成 Token;可复用 KV 则进入 Store 的生命周期。
KV Cache 是多大的对象
对标准注意力层,一个请求的逻辑 KV 载荷可以近似写成:
$$
M_{KV} \approx 2 \times L \times N \times H_{kv} \times D_h \times b
$$
其中,2 表示 Key 和 Value,$L$ 是层数,$N$ 是缓存 Token 数,$H_{kv}$ 是 KV Head 数,$D_h$ 是 Head Dimension,$b$ 是每个元素的字节数。它说明:上下文越长,KV 容量近似线性增长;模型权重不变并不代表长对话的显存需求不变。
但这不是物理显存的精确账单。Tensor Parallel 分片、Block 填充、对齐、副本、元数据、Allocator 碎片和固定缓冲区都会改变实际占用。设备峰值至少应按下式看待:
$$
M_{device,peak}=M_{weights}+M_{KV,live}+M_{workspace}+M_{transfer\ buffers}+M_{allocator\ margin}
$$
Mooncake 能把可复用、暂不活跃的 KV 转移到更大的资源池,但 Decode 正在使用的 KV、模型权重、Workspace 与传输缓冲仍需占用设备内存。
机制一:Prefill/Decode 解耦
解决什么
Prefill 是对整段输入做大矩阵计算,通常更偏计算吞吐;Decode 每步只产生少量 Token,却反复读取权重和历史 KV,更受显存带宽、批处理和尾延迟约束。把二者混在同一批次、同一实例,会产生资源干扰:长 Prefill 可能推高 Decode 的 Time Between Tokens,Decode 又会切碎 Prefill 的计算形状。
直觉上,Prefill 像批量录入档案,Decode 像实时逐字答复。两者需要的柜台节奏不同。 P/D 解耦把它们放入独立资源池,并用 KV 传输连接两个阶段。
| 对象 | 生产者 | 消费者 | 逻辑形状 | 生命周期 |
|---|---|---|---|---|
| Prompt Tokens | Gateway | Prefill | [S] |
单请求 |
| 隐状态 | 第 l 层 |
第 l+1 层 |
[B,S,H] |
层内 |
| 单层 KV | Prefill 第 l 层 |
Store / Decode 第 l 层 |
[2,S,H_kv,D_h] |
请求或缓存 |
| 完整 KV | 全部 Prefill 层 | Decode | [L,2,S,H_kv,D_h] |
Decode 全程 |
| 新 Token | Decode Step | 客户端和下一 Step | Token ID | 单步 |
1 | def serve_disaggregated(request, conductor, store, p_pool, d_pool): |
伪代码强调三件事:命中前缀和新增后缀是两个对象;层 KV 可以流式传输;完整 KV 在 Decode 生命周期内仍需保持。错误重试、背压和副本恢复在真实系统中必须实现,但不应从公开材料臆造细节。

图:根据 FAST’25 机制和固定版本公开接口重构的教学图,不是逐周期执行图。
适用性:Prefill/Decode 资源特征差异明显、上下文较长、负载可形成独立池时更有价值。代价:新增跨池 KV 传输、容量规划、故障域和调度复杂度;小 Prompt、低并发或慢网络下,解耦未必占优。其工程归属跨越推理运行时、调度、网络与容量管理,不是单一 Kernel 优化。
机制二:Mooncake Store 与 Transfer Engine
从“显存对象”变成“分布式对象”
PagedAttention 解决的是设备内 KV Block 的碎片和映射问题;Mooncake Store 进一步要回答跨实例问题:一个 Block 的键是什么、有哪些副本、放在哪里、谁能读、什么时候淘汰、数据如何绕过元数据服务直接传输。
论文描述的 Store 通常把连续 Token 切成 Block,通过前缀哈希识别,按副本和 LRU 管理。Block 大小是实现和实验参数,不是固定常数;FAST’25 的公开 Trace 格式使用 512-Token Block,但论文讨论的系统选择范围更宽。
| 对象 | 生产者 | 消费者 | 标识 | 放置 |
|---|---|---|---|---|
| Block Key | Store Client | Master/Index | 模型身份、Prefix Hash、Block 位置 | 元数据面 |
| Replica Metadata | Master | Store Client | Key 到 Segment/Location | Master 内存 |
| Segment | Store Client | Store Client | 注册地址和长度 | DRAM、SSD 或设备内存 |
| Transfer Batch | Client | NIC/DMA | 操作列表和 Batch ID | 数据面 |
| Completion | Transport | Caller | Batch/Operation 状态 | 客户端状态 |
1 | def cache_block(store, transfer, key, source_region, replica_targets): |

图:固定开源版本语义的教学重构。Master 管位置和副本;正常载荷由 Client 到 Client 传输,不经 Master 中转。实际介质、拓扑、租约与恢复策略随部署变化。
当前开源代码可直接看到 Store 的 put/get/batch_put/batch_get 路径,以及 Transfer Engine 的内存注册、Batch 分配、传输提交和状态查询;设计文档还明确区分 Master 元数据路径与客户端数据路径。参见固定版本的 Store C API、Transfer Engine C API 和 Store 设计。
机制三:KVCache-centric 调度
命中只是输入,不是目标
传统负载均衡常看队列,Prefix Cache Router 常看最长命中。Mooncake 的调度问题是二者的合并:一个实例命中更多 KV,却可能排队更久;另一个命中少,但计算资源空闲;远端 KV 的位置还会改变传输成本。
论文将首 Token 的估算拆成:
$$
\widehat{TTFT}=T_{transfer}+T_{queue}+T_{prefill}
$$
Decode 侧还需要单独检查 TBT 风险。若没有候选满足 SLO,系统可以提前拒绝请求,而不是先占用昂贵资源、最后才超时。这样改善的是 goodput,即满足 SLO 的有效吞吐,而不是凭空创造物理容量。
| 对象 | 来源 | 去向 | 生命周期 |
|---|---|---|---|
| Prefix Block Hashes | 请求 Token | Store Index | 本次调度 |
| 每实例命中长度 | Index | Cost Model | 本次决策 |
| 队列与传输估计 | Telemetry/Topology | Cost Model | 决策窗口 |
候选 (P,D) |
Router | Admission | 本次决策 |
| SLO Verdict / HTTP 429 | Admission | Gateway | 请求准入 |
1 | def schedule(request, p_instances, d_instances, index, slo): |

图:论文调度语义的教学重构。固定版本开源 Conductor 明确提供完整 Block 前缀哈希扫描、首个 Miss 停止、记录各实例最长命中并由 Router 选实例;这不足以证明 Kimi 全量生产成本模型已经开源。参见 Conductor 设计。
这里的伪代码用于展示决策闭环,不声称复现生产权重、预测器或并发保留协议。真正上线还要校准 P50/P99 预测误差、陈旧遥测、请求取消、租约、重试和副本扩散。
机制四:Chunked Pipeline Parallelism
超长 Prefill 仍然太慢怎么办
即使 P/D 已解耦,一个超长 Prompt 仍可能独占一条 Prefill 计算路径。Mooncake 的 CPP 将输入切成多个 Chunk,让不同 Chunk 在不同 Pipeline Stage 上重叠推进。它不是把注意力依赖凭空删除,而是改变 Chunk 的计算位置与时间安排,并按 Token 顺序组装最终 KV。
| 对象 | 生产者 | 消费者 | 逻辑形状 | 生命周期 |
|---|---|---|---|---|
| Chunks | Splitter | Prefill Stages | N × [B,C,H] |
Prefill |
| Boundary State | Stage i |
Stage i+1 |
Chunk Hidden State | Pipeline Wave |
| Chunk KV | Attention Layers | KV Collector | N × [L,2,C,H_kv,D_h] |
请求 |
| Full KV | Ordered Concat | Decode | [L,2,S,H_kv,D_h] |
Decode |
1 | def chunked_pipeline_prefill(tokens, stages, chunk_size): |

图:根据 FAST’25 §3.3 重构的 CPP 教学图,不等同于未公开的生产执行计划。Chunk 是物理切片,完整 KV 是按 Token 位置组成的逻辑和物理缓存集合。
CPP 更适合超长输入、单节点 TTFT 已成为主瓶颈且跨 Stage 通信可控的场景。短输入仍可走普通 Prefill 路径;否则固定 Pipeline Group、气泡、边界通信和调度复杂度可能抵消收益。
论文结果该怎样读

图:Mooncake 论文 Figure 1 的原始曲线裁切。横轴是 Token 间隔,纵轴是 Effective Request Capacity Ratio;三条竖线对应论文选定的 TBT Threshold。来源:FAST’25 论文。
这张图最有价值的不是“Mooncake 比 vLLM 快”这一句,而是它把容量定义为满足 TBT 门槛的有效请求容量。在论文的 Conversation 工作负载、16 个节点(每节点 8 × A800)和 vLLM 0.5.1 变体基线下,作者报告三档门槛分别提升 **498%、157% 和 59%**。
这些数字能证明:在该实验包络内,把 KV 复用、P/D 资源与 SLO 联合调度,可以显著扩大有效容量。它们不能证明:
- 单独启用 Prefix Cache 就会获得相同收益;
- 任意模型、卡型、网络和上下文分布都按同一比例提升;
- 曲线是单请求延迟、平均吞吐或物理 GPU 算力的直接提升;
- 当前开源版本在未经调优的集群上可以自动复现实验。
论文还报告,相比此前系统,历史 Kimi 生产工作负载容量提高 **115% 和 107%**,并在当时运行于数千节点、日处理超过 1000 亿 Token。这是有价值的生产规模证据,但仍属于作者报告的历史比较,不是跨系统、跨版本的独立统一 Benchmark。
什么时候值得采用
Mooncake 类架构通常适合以下组合:
- 高前缀复用:多轮对话、共享 System Prompt、Agent 工作流或长文档反复追问。
- KV 容量成为约束:GPU 显存无法保留足够多的热前缀,而主机内存、SSD 或远端内存可利用。
- P/D 特征差异明显:可分别扩缩容,并能用高速网络承接 KV 跨池传输。
- SLO 比裸吞吐重要:系统按 TTFT/TBT 的有效请求而不是提交请求数评估容量。
- 有能力维护控制面:具备遥测、预测、准入、注册内存、故障处理和一致性治理。
不应只因为“上下文很长”就直接采用。如果请求几乎没有共享前缀、网络慢、并发低、Prompt 很短,或者团队无法承担分布式缓存控制面的复杂度,设备内 Prefix Cache、Continuous Batching、PagedAttention 或更简单的 P/D 架构可能更合适。
常见误解
- “Mooncake 就是 P/D 解耦。” P/D 是骨架;分布式 KV Store、传输、缓存感知调度和长输入 CPP 才让骨架成为完整系统。
- “缓存命中越长越好。” 长命中仍可能因远端传输和排队失败。正确目标是满足 SLO 的联合成本。
- “KV 放到 CPU/SSD 后,GPU 就不需要 KV。” Decode 活跃 KV 仍要被高速访问;外部 Store 主要承接可复用或暂不活跃状态。
- “Master 是 KV 数据代理。” 公开 Store 设计中,Master 管理元数据,正常数据由客户端之间直接传输。
- “开源仓库等于 Kimi 生产调度器。” 开源代码提供可复用组件和明确接口,但不能据此补全未公开的生产预测模型、准入政策和运维系统。
- “论文提升可以直接套到我的集群。” 必须先对齐模型、负载、基线、卡型、网络、SLO 与指标定义。
总结
Mooncake 的工作可以归纳为四步:把异质的 Prefill/Decode 分开,把 KV Cache 从设备私有状态变成分布式可复用对象,让调度器比较复用、传输、排队、计算和 SLO 的总成本,再用 CPP 处理极长 Prefill 的关键路径。
它真正改变的是推理系统的优化单位:不再只优化某个 Kernel、某张卡或某个 Batch,而是优化一个请求携带的计算与状态在整个集群中的生命周期。理解这一点,比记住某个百分比更重要。
参考资料
- Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving,FAST 2025。
- Mooncake 开源仓库,本文源码语义固定于
bfca1ce2af8419c50dc8d464820a95d97d43c930。 - Mooncake README:组件概览。
- FAST’25 Trace 格式与请求字段。
- DistServe,OSDI 2024。
- PagedAttention / vLLM,SOSP 2023。