TT Lab
博客

한국어 English 日本語 中文

开始
博客

博客

NVIDIA Dynamo:分离 Prefill 与 Decode,并发送至存有 KV 的位置

状态:草案(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 上会互相干扰

긴 프롬프트가 끼어들 때 디코드에 생기는 일 요청 A 가 15ms 마다 토큰을 내는 중, 긴 프롬프트 B 가 들어온다 (가) 한 GPU 에서 함께 GPU B 프리필 A 의 다음 토큰이 227ms 늦다(실측) (나) 프리필·디코드 분리 디코드 GPU B 의 토큰 → 프리필 GPU B 프리필 KV 전송 0ms 200ms 400ms 600ms · 분리하면 A 의 토큰 간격은 고르게 유지된다. · 대신 B 의 첫 토큰에 KV 를 옮기는 시간이 더해진다. 전송 시간 = 토큰당 KV × 입력 토큰 ÷ 링크 속도 227ms: 8GB급 GPU·vLLM 기본 청크 2,048 실측. 전송 길이는 설명용.
图:长 Prompt 插入 Decode 时的情形以及分离时的情形

在第 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 稍微变晚了。 分块只能分担干扰,而无法消除干扰。

最早系统性地探讨分离式服务的两篇论文指出了这个问题。

2. 分离式服务:分离并移动 KV

方法很简单。 分别设置专用的 Prefill GPU 和专用的 Decode GPU。 当 Prefill GPU 生成 Prompt 的 KV 后,将该 KV 发送到 Decode GPU,Decode GPU 在接收到的 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: 분리 서빙과 KV 인지 라우팅 프런트엔드 OpenAI 호환 API · 토큰화 KV 인지 라우터 워커마다 비용 = 새로 계산할 프리필 블록 (이미 가진 블록은 뺌) + 디코드 부하 → 가장 싼 곳 블록 색인 워커 1: ■■■□ 워커 2: ■□□□ 프리필 워커 계산 위주 · 큰 텐서 병렬 등 워커 1 워커 2 디코드 워커 메모리 위주 · 큰 배치 워커 3 워커 4 NIXL 로 KV 전송 NVLink · RDMA(UCX) · TCP · 저장소(GDS 등) ↑ 워커가 블록 저장·삭제 이벤트를 라우터에 알림 플래너 대기열·KV 사용률·지연 목표를 보고 프리필·디코드 워커 수를 늘리고 줄인다 KV 오프로딩 GPU → CPU → 디스크 → 객체 KVBM(1.5 에서 폐지 예고) 또는 LMCache 등 엔진 연결
图:Dynamo 的架构:前端、KV 感知路由器、Prefill 与 Decode Worker、NIXL、Planner

Dynamo 是一个在 vLLM、SGLang、TensorRT-LLM 等引擎 之上 将多个 GPU 和多个节点连接起来的服务框架。它不替代引擎,而是负责如何划分多个引擎以及将它们发送到哪里。在文档 (v1.5.1) 中确认的架构如下。

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 发布的性能数据如下。全部为 厂商发布,未经亲自复现。

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

分离式服务。 结果恰好相反。所有情况都比独立服务要慢。

配置(并发 1) 1500 单词 3000 单词
8GB 级 GPU 独立运行 78ms 172ms
将单张 GPU 拆分为 Prefill 和 Decode 进程 406ms 812ms
拆分到两台不同的服务器(1GbE 级链路) 1,721~1,752ms 3,407~3,533ms

这并不是说“分离式服务很慢”,而是**“通过慢链路拆分就很慢”**。论文之所以以 NVLink 或 InfiniBand 为前提,原因就在这张表中。

6. Dynamo 与 LMCache 的关系

两者并非竞争关系,而是处于不同的层级。LMCache 是 在单个引擎旁存储和加载 KV 的缓存层,而 Dynamo 是 将多个引擎组合、拆分并进行分发和调度的框架。我们在文档中确认的集成点如下:

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 资源)还要大,那就是得不偿失。因此,分离没有收益或反而有害的情况包括以下几种:

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 的一句话: 让练习发球的人和练习拉球(对打)的人共用一张球桌,两人都会因为互相等待对方接球而吃亏。把球桌分开就好了。但是,如果装球的筐必须从隔壁大楼运过来呢?那种情况下,还不如一起打。在决定拆分之前,先测一下运送球筐的速度有多快吧。

参考资料

登录后即可点赞

评论

还没有评论。

登录后即可发表评论