状态:草案(2026-10-13),部分实测。 论文、官方文档和 NVIDIA 博客已于 2026-10-13 直接打开确认,文档基于 Dynamo v1.5.1(2026-10-07)。NVIDIA 发布的性能数据标记为“厂商发布”。实测数据重新引用自同一网站的“Toss ML/AI Infra 准备”第 14 篇(8GB 级别 GPU,vLLM)和第 24 篇(Dynamo 1.6.0 开发版,8GB 和 24GB 级别 GPU,0.6B 模型)。通过 NVLink 和 RDMA 连接的环境下的分离式服务收益未作实测。 编写规则:实测数据为基础,未能测量的标记为“未实测”,无法确认的标记为“未确认”。
NVIDIA Dynamo:分离 Prefill 与 Decode
目录
- 1. Prefill 与 Decode 在同一个 GPU 上会互相干扰
- 2. 分离式服务:分离并移动 KV
- 3. NVIDIA Dynamo 的架构
- 4. 为什么吞吐量会上升
- 5. 亲自实测的 Dynamo
- 6. Dynamo 与 LMCache 的关系
- 7. 什么时候没有收益
- 8. 系列总结
- 参考
1. Prefill 与 Decode 在同一个 GPU 上会互相干扰
在第 1 篇中提到过,Prefill 绑定于计算,而 Decode 绑定于内存带宽。如果两者共用一个 GPU,就会产生问题。连续批处理(Continuous Batching)将新请求的 Prefill 插入到 Decode 步骤之间,Prefill 较长的步骤需要很长时间,在此期间批处理中的其他请求无法接收下一个 Token。
我们的实测。 在 8GB 级别 GPU 上,使用 vLLM 默认设置(单步输入上限 2,048 个 Token),在正在进行 Decode 的请求旁边插入一个 3,500 个 Token 的输入时,该区间的最大 Token 间隔为 227ms(3 次测量分别为 227、226、226ms)。平时的间隔大约为 15ms。通过第 2 篇中的分块 Prefill(Chunked Prefill),虽然可以将该值缩减至 69ms,但代价是长输入的第一个 Token 稍微变晚了。 分块只能分担干扰,而无法消除干扰。
最早系统性地探讨分离式服务的两篇论文指出了这个问题。
- DistServe(Zhong 等,OSDI 2024):认为如果将两者放在同一个 GPU 上,(1) 两个阶段会互相拖慢,Prompt 越长越严重;(2) 两个阶段必须使用 相同的资源和相同的并行化设置,这导致必须迎合 TTFT 和 Token 间隔目标中更苛刻的那一个,从而过度配置 GPU。论文评价称,分块 Prefill 只是在 TTFT 和 Token 间隔之间做权衡。
- Splitwise(Patel 等,ISCA 2024):通过分析实际云端记录,证明了 Prompt 阶段以计算为主,而 Token 阶段以内存带宽和容量为主。在 BLOOM-176B 中,处理 1,500 个 Token 的 Prompt 所花费的时间与生成 6 个输出 Token 的时间相同,并且即使将 Token 阶段的 GPU 功耗从 700W 降至 350W,延迟也几乎没有增加。得出的结论是,如果性质如此不同, 使用不同的硬件或不同的配置会更好。
2. 分离式服务:分离并移动 KV
方法很简单。 分别设置专用的 Prefill GPU 和专用的 Decode GPU。 当 Prefill GPU 生成 Prompt 的 KV 后,将该 KV 发送到 Decode GPU,Decode GPU 在接收到的 KV 基础上继续生成 Token。
- 由于 Decode GPU 不会受到长 Prefill 的干扰,Token 间隔非常均匀。在满足间隔目标的同时, 可以设定更大的 Decode 批处理量 。
- 可以为两个阶段赋予 不同的并行化和不同的 GPU 数量。Prefill 侧重于划分计算,而 Decode 侧重于容纳更大的批处理。
- 代价是 KV 传输。按照第 1 篇中的公式,KV 非常大,必须在第一个 Token 生成之前将其传输完毕。
DistServe 的结果。 在 A100 80GB(节点内 NVLink,节点间 25Gbps)、OPT-13B·66B·175B 上测量了 90% 以上满足延迟目标的最大请求率(goodput)。
| 工作负载 | 模型 | 相比 vLLM 的请求率 | 相比 vLLM 的延迟目标 |
|---|---|---|---|
| 聊天机器人 (ShareGPT) | OPT-13B·66B·175B | 2.0~4.6倍 | 1.8~3.2倍严格 |
| 代码补全 (HumanEval) | OPT-66B | 5.7倍 | 1.4倍严格 |
| 摘要 (LongBench) | OPT-66B | 4.3倍 | 12.6倍严格 |
如果与其他基准(DeepSpeed-MII)相比,最高可达 7.4 倍,摘要中的“请求率最高 7.4 倍或延迟目标严格 12.6 倍”是这两张表格合并后的数值。同步示例也很直观。如果将 13B 模型放在一张 A100 上,大约可以达到 1.6 个请求/秒,而仅进行 Prefill 时为 5.6,仅进行 Decode 时为 10 个请求/秒;如果拆分为 2 张 Prefill + 1 张 Decode,则每个 GPU 达到 3.3 个请求/秒,提升了 2.1 倍。
KV 传输情况如何?论文计算得出,OPT-66B 的一个 512 Token 请求对应约 1.13GB 的 KV,因此每秒 10 个请求就需要 13.3GB/s 的带宽。因此,设计上将 Prefill 和 Decode 部署在 同一节点内 (NVLink) ,其结果是,在 OPT-175B 中传输开销占总延迟的比例不到 0.1%。
Splitwise 的结果。 将 KV 逐层异步地 发送,与下一层的计算重叠(InfiniBand)。未能重叠的传输在 A100 上约为 8ms,在 H100 上约为 5ms,占 Prompt 计算时间的 7% 以下,并为总延迟增加了 0.8%。在功耗相同的条件下,仅由 A100 划分的配置比基准(A100)的吞吐量高出 2.15 倍(正文图 18a)。摘要中的代表性数值(“成本降低 20% 的同时提升 1.4 倍”、“相同成本和功耗下提升 2.35 倍”)无法在正文实验中找到完全相同的配对,此处仅记录正文数值。
3. NVIDIA Dynamo 的架构
Dynamo 是一个在 vLLM、SGLang、TensorRT-LLM 等引擎 之上 将多个 GPU 和多个节点连接起来的服务框架。它不替代引擎,而是负责如何划分多个引擎以及将它们发送到哪里。在文档 (v1.5.1) 中确认的架构如下。
- 前端:OpenAI 兼容 API,Token 化。
- KV 感知路由器:决定将请求发送到哪个 Worker。计算每个 Worker 的成本并选择成本最低的一个。v1.5.1 的成本公式为:“该 Worker 中需要重新计算的 Prefill 块数量(已拥有的块扣除)× 权重 + Decode 块负载 + 运行中的请求数 × 权重”。 已经拥有相同首部 KV 的 Worker 的 Prefill 部分会减少,因此成本更低。 不过,为了避免请求过度集中于某一个地方,也会同时考虑负载。文档解释称,增加对首部重叠的加权可以减少 TTFT,而减小加权则会使负载更均匀地分散,从而减少 Token 间隔。
- 了解 Worker 拥有什么内容的方法:默认方式是每当 Worker 存储或删除块时发送事件,由路由器建立索引;也存在不发送事件、而是通过记住“最近发送的请求”来进行估算的近似模式(默认 TTL 120 秒)。
- 分离式服务:有专门选择 Prefill Worker 的路由器,在 Prefill Worker 生成 KV 后,由 Decode Worker 通过 NIXL 直接获取该 KV。
- NIXL:一个将 GPU 内存、CPU 内存、文件、对象存储之间的传输包装为统一接口的库。实际传输由插件负责(UCX 为默认,还支持 GPUDirect Storage、POSIX、Mooncake、libfabric、对象存储等)。根据情况使用 NVLink、InfiniBand / RoCE 等 RDMA、PCIe 以及 TCP。
- Planner:根据负载调整 Prefill 和 Decode Worker 的数量。拥有吞吐量目标(队列深度、KV 利用率,默认)、延迟目标(TTFT、Token 间隔 SLA)等模式,并采用预测即将到来的请求数、输入输出长度、缓存命中率来确定的方法,以及对引擎各步骤指标进行回归的方法。在 Kubernetes 中,由 Operator 来匹配其数量。
- KV 块管理器 (KVBM):这是一个将 KV 下沉到 GPU(G1) → 固定主机内存(G2) → 本地磁盘(G3) → 对象存储(G4)的层级结构。 在 v1.5.0 发布说明中已被改为 deprecated,并预计在 v1.7.0 中移除。官方建议将主机和磁盘层迁移到引擎自身的卸载功能(或类似 LMCache 的连接)。
4. 为什么吞吐量会上升
| 来源 | 改变了什么 | 依据 |
|---|---|---|
| 消除干扰 | Decode GPU 不会插入长 Prefill,在遵守 Token 间隔目标的同时增大 Decode 批处理量 | 实测(干扰 227ms),DistServe・Splitwise |
| 阶段定制 | 为 Prefill 和 Decode 提供不同的并行化、GPU 数量、硬件。Planner 根据负载调整比例 | DistServe(2.1倍示例),Splitwise |
| 缓存命中 | 发送到具有相同首部的 Worker,从而跳过 Prefill 本身 | 实测(第 5 节),厂商发布 |
| 划分工作集 | 首部按 Worker 分流,每个 Worker 的 GPU 缓存中只装入各自的部分 | 实测(第 5 节) |
NVIDIA 发布的性能数据如下。全部为 厂商发布,未经亲自复现。
- 介绍博客(2025-03-18):在 GB200 NVL72 上使用分离式服务运行 DeepSeek-R1 671B(FP4,输入 32K,输出 8K),吞吐量最高提升 30 倍;在 Hopper 上使用 Llama 70B(FP8,输入 3K,输出 50)提升 2 倍以上。图注中写着“预估性能,可能会有变动”。
- 文档 v0.9.0 的设计文档:分离式服务在 Llama 70B 系列(FP8、H100、输入 3K·输出 150)上实现了单节点每块 GPU 处理量 +30%,2 个节点时达到 2 倍以上。KV 感知路由在向 H100 2 节点发送 10 万个实际请求(平均输入 4K·输出 800)时,相比随机路由,TTFT 减少了 3 倍,平均延迟减少了 2 倍。KVBM 的 CPU 卸载在 Qwen3-8B(H100、多轮对话、平均输入 20K)中,比仅使用 GPU 前缀缓存时 TTFT 提升了 2.2~12 倍。
5. 亲自实测 Dynamo
我们在另一个系列中,使用 Qwen3-0.6B(每个 Token 的 KV 为 114,688 字节)对 Dynamo(1.6.0 开发版,vLLM 0.30.0,NIXL 1.3.2)进行了重新测试。
KV 感知路由。 启动了两个 Worker,将约 1500 个单词的前缀 12 种混排后各发送 6 次(共 60 次重复请求)。如果重复请求路由到具有相同前缀 KV 的 Worker,首字延迟(TTFT)约为 15ms,否则约为 80ms。
| 路由方式 | 60 次中的命中次数(3次) | 平均首字延迟 (TTFT) |
|---|---|---|
| 轮询 (Round-Robin) | 35, 40, 43 | 34~42ms |
| 随机 | 44, 31, 45 | 32~46ms |
| KV 感知,近似模式 | 60, 53, 60 | 15~26ms |
| KV 感知,事件模式但无事件 | 39, 44, 41 | 32~38ms |
| KV 感知,事件模式 | 60, 60, 60 | 15ms |
- 开启路由器后,命中率接近 100%。
- 需要注意静默失败(Silent Failure)。 开启了事件模式但 Worker 没有发送事件时,路由器的索引会变空,命中率降至随机水平,且没有任何错误,仅留下一条日志警告。开启路由后,必须亲自测试「再次发送相同前缀时首字延迟是否会缩短」。
- 轮询并不比随机好。单个 Worker 的 KV 容量(14,816 个 Token)无法容纳全部 12 种前缀(约 18,000 个 Token),而 KV 感知路由将前缀按 Worker 分配了 6 种,让各自完整容纳。路由带来的优势除了“发送到相同位置”外,还叠加了“每个 Worker 的工作集变小”的效果。
- 经过前端的开销在空闲时约为 13ms,在并发 8 和 32 时没有明显区别。
分离式服务。 结果恰好相反。所有情况都比独立服务要慢。
| 配置(并发 1) | 1500 单词 | 3000 单词 |
|---|---|---|
| 8GB 级 GPU 独立运行 | 78ms | 172ms |
| 将单张 GPU 拆分为 Prefill 和 Decode 进程 | 406ms | 812ms |
| 拆分到两台不同的服务器(1GbE 级链路) | 1,721~1,752ms | 3,407~3,533ms |
- 如果拆分单张 GPU,计算资源不会增加,只会增加 KV 传输。这种配置下并没有 GPU 去解决分离想要解决的问题。
- 当拆分到两台服务器时,增加的时间与 KV 字节 ÷ 链路吞吐量完全吻合。传输单个 3000 单词的请求耗费了 351.75MB、3,374ms、104MB/s,Prefill 耗时 83ms 加上约 3.4 秒的传输时间与测得的结果一致。无论哪张 GPU 负责 Prefill 几乎都一样。这是因为时间被链路所限制,而不是被计算所限制。
这并不是说“分离式服务很慢”,而是**“通过慢链路拆分就很慢”**。论文之所以以 NVLink 或 InfiniBand 为前提,原因就在这张表中。
6. Dynamo 与 LMCache 的关系
两者并非竞争关系,而是处于不同的层级。LMCache 是 在单个引擎旁存储和加载 KV 的缓存层,而 Dynamo 是 将多个引擎组合、拆分并进行分发和调度的框架。我们在文档中确认的集成点如下:
- 聚合配置(单个 Worker 兼顾 Prefill 和 Decode): Dynamo 的 vLLM Worker 通过
LMCacheMPConnector(角色kv_both)向节点的lmcache server读写 KV。由于 Worker 和 LMCache 服务器通过 CUDA IPC 连接,因此在 Kubernetes 中需要hostIPC: true。v1.5.1 的 Kubernetes 指南仅涵盖了这种聚合配置,单独列出了经过验证的版本组合,并警告称如果服务器和 LMCache 的版本不同,通信协议将无法匹配。 - 分离配置: v1.3.0 的文档举例说明了在 Prefill 端同时打包使用 LMCache 连接器和 NIXL 连接器的场景。Prefill 到 Decode 的传输由 NIXL 负责,而 LMCache 负责请求之间的复用,这是一种分工合作。LMCache 文档中的分离配置也是同样的形态(第 3 部分第 7 节)。在 v1.5.1 中,我们未能找到将 LMCache 与分离式服务结合使用的官方流程(未确认)。
- 与 KVBM 的关系: Dynamo 的卸载概述文档将 LMCache、SGLang 的 HiCache 和 FlexKV 作为替代方案介绍,并建议 不要叠加使用。KVBM 从 v1.5.0 开始已被标记为废弃(deprecated)。
- 路由器的考量范围: v1.5.1 的路由器支持表中写明,vLLM 自带卸载、SGLang HiCache、TensorRT-LLM 的 Host/Disk 命中情况会被计入评分(Host 命中 0.75,Disk 命中 0.25),但 没有 LMCache 行 。因此,我们无法通过文档确认路由器是否将保存在 LMCache 中的 KV 纳入评分(未确认)。
7. 什么时候没有收益
分离式服务的盈亏可以用类似于第 3 部分的公式来估算: 附加到首字延迟的时间 ≈ 每个 Token 的 KV 大小 × 输入 Token 数 ÷ 链路吞吐量(由于按层传输,部分时间可以与计算重叠并隐藏)。计算传输 4,096 个 Token 的 KV 所需的时间如下(仅传输时间,不含计算)。
链路速度方面,1GbE 级在我们实际测试中的有效吞吐量为 104MB/s,100Gb/s 的理论值为 12.5GB/s,而 NVLink 级根据 DistServe 论文所述,在 A100 之间为 600GB/s。
| 模型 | KV 大小 | 1GbE 级 | 100Gb/s | NVLink 级 |
|---|---|---|---|---|
| Qwen3-0.6B | 470MB | 4.5 秒 | 38ms | 0.8ms |
| Llama 3.1 8B | 537MB | 5.2 秒 | 43ms | 0.9ms |
| Llama 3.1 70B | 1.34GB | 12.9 秒 | 107ms | 2.2ms |
如果这个数值比能够节省的开销(因干扰而变慢的 Decode 阶段、过度预留的 GPU 资源)还要大,那就是得不偿失。因此,分离没有收益或反而有害的情况包括以下几种:
- 链路很慢。 上表的第一列就是这种情况,实测中慢了 20 倍以上。
- 提示词很短。 如果 Prefill 很短,插入到 Decode 中的时间也很短,能够消除的干扰就很少。相反,传输和路由的固定开销却依然存在。
- 负载较低。 如果同时进行 Decode 的请求很少,就没有需要免受干扰的对象。由于分离会将 GPU 拆分为二,在空闲时只会增加闲置的 GPU。
- 只有单张 GPU。 即使拆分,计算资源也不会增加(实测慢了 4.7~7.2 倍)。
- 小模型。 Prefill 本身就已经很便宜了(0.6B 的 Prefill 耗时 83ms),导致 KV 传输的占比相对变大。
Dynamo 文档也提到并没有普遍适用的门槛。由于边界会根据模型、GPU、输入长度分布而变化,早期版本(v0.1.0)仅在“减去前缀命中的 Prefill 长度超过门槛且远程 Prefill 队列较短时”才使用远程 Prefill。而在 v1.5.1 中,根据路由器开销进行条件拆分的功能已进入实验阶段。 最稳妥的做法是:先测试自己链路的 KV 传输吞吐量, 用该数值代入上述公式计算后再做决定。
KV 感知路由则情况不同。由于它无需传输 KV,而是 将请求迁移到 KV 所在的位置 ,因此没有链路开销。如果是相同前缀反复出现的负载场景,相对而言不容易吃亏。不过,需要调整负载权重以避免请求涌向单个 Worker,并确认事件是否确实在发送。
8. 系列总结
| 篇章 | 节约了什么 | 何时效果最大 | 何时没有效果 |
|---|---|---|---|
| 1. KV 缓存 | 过去 Token 的 K·V 重新计算 | 始终有效(输出相同时) | — 代价是占用内存 |
| 2. PagedAttention·连续批处理·前缀缓存 | 内存浪费、空置槽位、相同前缀的计算 | 并发请求多时、存在公共提示词 | 工作集大于 GPU 容量时缓存被清空 |
| 3. LMCache | 用 GPU 外的 KV 替代 Prefill | 长上下文、高复用率、快速存储路径 | 短输入、低命中率、慢链路、小容量 |
| 4. Dynamo | 消除干扰、分阶段定制、向 KV 侧路由 | 高负载、长提示词、高速 GPU 间链路 | 慢链路、单卡、低负载、小模型 |
贯穿这四篇文章的核心问题只有一个: “重新计算这些 KV 与从某处获取它们,哪个成本更低?” 答案取决于模型的每 Token KV 大小、GPU 的计算速度、KV 传输路径的速度以及相同前缀再次出现的频率。这四项都是可以实际测量的数据。
Tee 的一句话: 让练习发球的人和练习拉球(对打)的人共用一张球桌,两人都会因为互相等待对方接球而吃亏。把球桌分开就好了。但是,如果装球的筐必须从隔壁大楼运过来呢?那种情况下,还不如一起打。在决定拆分之前,先测一下运送球筐的速度有多快吧。
参考资料
- Zhong 等人,DistServe: Disaggregating Prefill and Decoding for Goodput-optimized LLM Serving (OSDI 2024): https://arxiv.org/abs/2401.09670 (v3, 第 1·2.3·3.3·6 节, 表 1, 图 8·9·10)
- Patel 等人,Splitwise: Efficient Generative LLM Inference Using Phase Splitting (ISCA 2024): https://arxiv.org/abs/2311.18677 (v2, 第 3·4.C·6 节, 图 18), Microsoft Research 页面: https://www.microsoft.com/en-us/research/publication/splitwise-efficient-generative-llm-inference-using-phase-splitting/
- NVIDIA Dynamo 仓库与发布: https://github.com/ai-dynamo/dynamo (v1.5.1, 2026-10-07), 文档: https://docs.nvidia.com/dynamo/ (架构、路由器概念与配置、分离式服务、规划器、KVBM 配置、KV 卸载与 LMCache MP 部署、路由器卸载支持表,访问于 2026-10-13), 早期版分离式服务文档: https://github.com/ai-dynamo/dynamo/blob/v0.1.0/docs/disagg_serving.md
- NIXL: https://github.com/ai-dynamo/nixl (README,
docs/nixl.md) - NVIDIA 介绍博客(官方发布): https://developer.nvidia.com/blog/introducing-nvidia-dynamo-a-low-latency-distributed-inference-framework-for-scaling-reasoning-ai-models/ (2025-03-18), 设计文档 v0.9.0(官方发布): https://docs.nvidia.com/dynamo/v-0-9-0/design-docs/overall-architecture
- LMCache 的 Dynamo 集成文档: https://docs.lmcache.ai/production/dynamo_coordination.html
- 实测引用:同一网站的“Toss ML/AI Infra 准备”第 14 篇(Chunk 与干扰)、第 24 篇(Dynamo 实测)