跳到正文
vLLM Blog· Inferact and the vLLM Team·· 2 天前精选AI 评分70

vLLM 在 GB300 NVL72 上规模化服务 DeepSeek-V4.1-Flash,解码吞吐与 DeepInfer 差距在 6% 以内

Serving DeepSeek-V4.1-Flash at Scale: vLLM Matches DeepInfer and Scales to GB300 NVL72

AI 导读

vLLM 团队在单台 NVIDIA GB300 NVL72 上以 P/D 分离和 Wide-EP 服务 DeepSeek-V4.1-Flash,在 SemiAnalysis AgentX 上达到每 GPU 954K tokens/s、单用户 P90 196 tokens/s,按 DeepSeek 低谷电价折算为每 GPU 小时 38.96 美元。

推荐理由

vLLM 团队公开了在 GB300 NVL72 上服务 DeepSeek-V4.1-Flash 的完整调优过程,逐项给出优化手段与实测增益,可作为大规模推理部署的参考。

正文 · AI 翻译

TL;DR:在一台 NVIDIA GB300 NVL72 机架上,采用 P/D 分离和 Wide-EP 的 vLLM 在 SemiAnalysis AgentX 上为 DeepSeek-V4.1-Flash 提供服务,达到每 GPU 每秒 954K tokens,每用户 P90 为每秒 196 tokens,是我们在第一篇文章中单节点结果的7.9 倍,按 DeepSeek 的错峰价格为每 GPU 小时 38.96 美元。一条专用解码路径可为单个用户达到每秒 826 tokens。与 DeepSeek 自研引擎 DeepInfer 相比,vLLM 的解码吞吐在批大小 8–256 范围内差距在6%以内,其预填充也贴合 DeepInfer 公布的曲线。

效率来自对 vLLM 已有组件的刻意工程优化,并构建在 DeepSeek 开源的 kernel 之上。本文介绍我们的性能研究,逐项拆解每项优化,并分享我们得到的经验:

  • 通用引擎可以匹敌专用引擎
  • 先理解模型,再优化
  • 小型 DEP 实例最适合预填充1
  • Wide-EP 解码借助 EPLB 扩展良好
  • 在 NVL72 规模下,CPU 开销变得关键
  • 专用解码路径实现低延迟

性能概览

图 1:NVIDIA GB300 NVL72 上的 SemiAnalysis AgentX:采用 P/D 分离和 Wide-EP 的 vLLM(金色)相比我们在第一篇文章中的聚合单节点结果,吞吐量进一步提升 7.9 倍。吞吐量统计缓存输入、未缓存输入和输出 token(来源)。

与 DeepInfer 对比

DeepInfer 是 DeepSeek 为 DeepSeek-V4.1-Flash 自研的推理引擎,本周作为离线引擎发布,并公布了预填充和解码曲线。它是该模型最相关的参照,因此在介绍我们的优化之前,先展示 vLLM 相对它的位置。

解码。在 DeepSeek 的解码配置下(131K 上下文,nextn=3),GB200 上的 vLLM 在批大小 8 到 256 范围内,吞吐与 DeepInfer 公布结果的差距在 6% 以内(图 2)。

图 2:131K 上下文、nextn=3 时每 GPU 解码输出吞吐 vs. 批大小。GB200 上的 vLLM vs. DeepInfer 公布结果,读取自其 README 中的图表(来源)。

预填充。DeepInfer 公布的预填充曲线使用 EP4DP4、32 个冗余专家和 140-token 有界重放,硬件未在图中说明,我们是从图中读取其数值。我们的运行使用 GB300 上的 DEP2,无冗余专家,128-token 重放,并使用我们自己的提示词。由于设置不同,我们不把两条曲线之间的差距解读为引擎对引擎的加速。图 3 表明的是,vLLM 的 DEP2 预填充在其公布范围内贴合 DeepSeek 自研引擎。

图 3:预填充吞吐 vs. 新 token 数。GB300 上的 vLLM DEP2 vs. DeepInfer 公布曲线(EP4DP4、32 个冗余专家、140-token 重放,硬件未说明),读取自其 README 中的图表(来源)。

这两个引擎之所以表现接近,是因为它们在两个方向上都有共同的渊源。DeepInfer 最初构建于 vLLM 之上,而 vLLM 又持续集成了 DeepSeek 库中的内核,包括 MegaAttn、MegaMoE 和 Mega-mHC,并围绕这些内核对技术栈的其余部分进行了大量优化。DeepInfer 在离线模式下针对单一模型;同一 vLLM 构建也在线服务该模型,采用 P/D 分离和跨整个 NVL72 机架的 Wide-EP,这正是本文其余部分所测量的内容。后续章节将描述这项工作。

底层揭秘:速度从何而来

先测量模型

在调优之前,我们先量化 DeepSeek-V4.1-Flash 的高效架构设计:

  • KV 缓存占用小。得益于跨层 KV 共享和 FP4 压缩,全局 KV 缓存每 token 仅占 890 字节(参见 DeepSeek-V4.1-Flash 技术报告)。
  • 轻量级注意力。第 2、8 和 14 层使用 2× 压缩进行全上下文索引。借助有界重放,第 20 层为所有 token 写入全局 KV,但仅对最后 128 个 token 运行索引和注意力;第 21–39 层仅处理这些 token。
  • 即使在长上下文中,解码也受 MoE 制约。见下方图 5。在 128K 上下文、每 rank 64 个请求的 DEP4 解码下,MoE 占目标步骤的 62%,而注意力和索引器合计仅占 13%。

下表展示了目标模型在 DEP32、每 rank 16 个请求、每请求 6 个 token(一个 token 加五个 DSpark 草稿 token)、所有请求上下文长度相同的情况下,在 GB300 上的前向时间。从 128K 到 855K,上下文增至 6.7 倍,目标模型解码延迟仅增加 0.6 ms(+7%)。

每请求上下文64K128K256K512K855K
目标前向(ms)8.868.939.039.259.53
对比 128K−0.8%–+1.1%+3.6%+6.7%

这些特性塑造了我们后续的优化策略:

  • 预填充应以较小的 DEP 规模运行。即使在 B300 或 GB300 上的 DEP2 实例也能容纳模型权重和许多并发会话的 KV 缓存。更小的 world size 大大简化了 DP/EP 负载均衡。
  • KV 容量很少限制批大小。KV 缓存可轻松放入 HBM,使我们能够将每个操作推向其计算或内存带宽极限,而不是围绕 KV 容量做文章。这也使我们的扫描保持一致且低噪声,没有抢占或 KV 缓存压力。
  • Wide-EP 对解码有效。MegaMoE 解码受权重读取制约,而 Wide-EP 直接削减了这一占主导地位的 MoE 成本。
  • 解码 DP 负载均衡更简单。该模型的解码步骤时间随上下文长度变化很小,因此 DP 负载均衡可以简化为按每 rank 请求数的最小负载。
  • 合成工作负载对解码仍具代表性。使用平均输入和输出长度可以很好地估计性能,而无需重放完整的 agentic 轨迹。

我们如何测量

在不使方法过于复杂的前提下准确测量性能并非易事。我们将其拆分为两个问题:预填充或解码步骤应花费多少,以及 DP 和 EP 不均衡带来多少额外开销?

  • Prefill 与 decode 步骤耗时。 vllm bench forward(#61339)测量的是精确的 prefill 或 decode 批次通过实际 execute_model 路径、跨 DP 和 EP rank 的模型前向耗时。这仅测量 GPU 时间,能给出干净的 trace。此外,vLLM 的 DecodeBenchConnector 测量给定并发下引擎级的端到端 decode 性能。仅 GPU 时间与服务步骤时间之间的差距揭示了意外的开销。
  • Prefill DP 不均衡:mirror 与 lag 重放。 Agentic trace 每次运行都会变化,因此 DP 不均衡很难隔离。为此,我们在每个 DP rank 上重放相同的请求。在 mirror 运行中,所有 rank 同时收到各自的请求。在 lag 运行中,rank r 在 r × 5 秒后收到相同的请求,因此各 rank 步调不一致,但完成的总工作量相同。两次运行之间的差异就是 DP 不均衡的代价。
  • Decode EP 不均衡:真实路由与均匀路由。 对每个 MoE 层,我们将 balancedness 定义为平均 rank 负载除以最大 rank 负载,按步骤并在 EPLB 的窗口内计算。作为均衡参考,我们用 token 均匀随机路由运行相同的 decode 批次。该参考仍存在采样噪声:在 DEP32、每 GPU 72 个请求时,均匀路由对 target(top-6 路由)达到约 0.96 的 balancedness,对 draft(top-3)达到 0.94。真实路由与均匀路由之间的差距是专家均衡最多能挽回的部分,而 EPLB 运行显示了它实际挽回了其中多少。

Prefill:DEP2 效果最佳

如上所述,较小的 DEP 规模对 prefill 有吸引力。在并发 256 的 AgentX 仅 prefill 运行中,DEP4 的每 GPU 吞吐仅为 DEP2 的 83%(53.3K 对 64.4K tokens/s)。关闭前缀缓存后的 mirror 和 lag 重放指向 DP 不均衡:当各 rank 步调不一致时,DEP4 损失了 13.6% 的吞吐。2 这使 DEP2 成为我们简单的默认选择。

每个实例的 prefill 吞吐(tokens/s)mirror(均衡)lag(不均衡)损失
DEP2138.7K130.5K5.9%
DEP4267.6K231.1K13.6%

隐藏在 trace 背后的优化

我们的第一篇博文涵盖了广泛的 prefill 优化。更干净的 trace 帮助我们识别出剩余的瓶颈,尤其是那些随上下文长度增长的瓶颈。例如,在两块 GB300 GPU 上,8K token 的 prefill 在没有先前上下文时耗时 87.9 ms,但在有 512K 缓存上下文时耗时 189.4 ms。我们解决了另外三个瓶颈:

将 SWA 有界重放扩展到第 20 层(#59894):32K 新 token 时 +19.9%

SWA 有界重放已将第 21–39 层限制为最后 128 个 token。此前,第 20 层仍对所有新 token 执行 indexer 计算。现在它为所有新 token 写入 KV,但仅在 128 token 的重放批次上运行其余计算。这使 prefill 吞吐在32K 新 token 时提升 19.9%,增益从 4K 时的 10.1% 增至 64K 时的 23.1%。

为共享 Engram 主机表使用 2 MB 页(#62359):32K 时再 +2.8%

Engram 从跨 DP rank 共享的主机表中执行随机读取。之前的 /dev/shm 映射使用 64 KB GPU 页,导致频繁的 GPU TLB 未命中。将表迁移到 host-NUMA cuMem 分配可启用 2 MB GPU 页,使 prefill 吞吐在32K 新 token 时再提升 2.8%。

在 prefill indexer 中使用 DeepSelect top-k(#62240):32K 时再 +15.6%

预填充索引器现在使用 DeepSelect 对候选块进行排序,与解码路径保持一致。其收益随参与排序的键数量增长而增大,在 32K 新 token 时进一步提升预填充吞吐量 15.6%,在 64K 时提升 15.2%。

综合来看,这些改动在 128K 缓存前缀的基础上,使 4K–64K 新 token 的预填充吞吐量提升 35.6–43.9%。在 32K 时,综合增益为 42.5%;在 64K 时,吞吐量从 71.2K 提升至 102.5K tokens/s/GPU(+43.9%)。

图 4:在 128K 缓存命中后,DEP2 上每 GPU 的新 token 预填充吞吐量,依次叠加 layer 20 replay、Engram 2 MB pages 和 DeepSelect top-k。

解码:扩展 Wide-EP 并用 EPLB 平衡专家

在解码侧,Wide-EP 配合 EPLB 已是成熟实践,DeepSeek 的推理系统概览中已有描述。vLLM 对两者的支持已有一段时间(参见我们的大规模服务博文),我们发现它们依然运行良好。本节聚焦于我们的新发现和实证经验。

Wide-EP 的扩展

我们在 128K 上下文、每 GPU 64 个请求的条件下,测量了从 DEP4 到 DEP32 的解码扩展性(已启用 EPLB;见下一节)。随着每个 rank 持有的专家数减少,目标 MegaMoE 时间从 13.4 ms 降至 6.0 ms,而其余工作仍保持在 10 ms 左右。因此,每 GPU 的吞吐量增益逐渐减弱。在 DEP32 时,draft 的通信开销也开始抵消更宽并行带来的收益。

图 5:在 NVIDIA GB200 上,128K 上下文、每 GPU 64 个请求时,从 DEP4 到 DEP32 每个 rank 的解码步时间,以及每 GPU 的输出吞吐量。

EPLB

我们让 EPLB 每 3,000 步根据前 1,000 步的负载重新排列专家。EPLB 将目标模型的均衡度从 0.35 提升至 0.94,将 draft 的均衡度从 0.21 提升至 0.89,分别弥补了与均匀路由之间约 97% 和 93% 的差距。

图 6:在 GB300 NVL72 上的解码,分别展示关闭 EPLB、仅对目标模型启用 EPLB,以及对目标模型和 DSpark draft 均启用 EPLB 的情况。标签页展示每步均衡度、DEP32 下的每步时间分解以及吞吐量(三次运行均值;柱条表示范围)。

两项改动实现了这一点。#62009 引入了基于 NVLink 的 symm_mem 后端,可在不停止解码的情况下于不到一秒内重新平衡整个 DEP32,将 EPLB 的副本映射和负载记录融合进 MegaMoE 内核(每步节省约 0.2 ms),并从解码循环中移除了主机同步。#61395 支持目标模型与 draft 模型异构时的 EPLB。DSpark draft 有 128 个路由专家、top-3 路由,而目标模型有 384 个专家、top-6 路由,因此 EPLB 分别跟踪每个模型的专家放置和负载,并对两者都进行重新平衡。

克服快速大规模解码中的 CPU 开销

Wide-EP 解码在每一层都会同步所有 rank,因此一个慢 rank 就会拖住整个实例。异步调度在小规模下能很好地隐藏 CPU 开销,但更多 rank 会从两方面使这变得更困难:GPU 步变得更短,留给 CPU 工作的余量更少;同时某个 rank 落后的可能性也更大。

在实践中,我们观察到未优化的 DEP32 比 DEP16 运行得更慢(每步 17.57 对 13.84 ms),尽管其 GPU 执行快了 1.1 ms。下表列出了我们找到的所有原因,按影响排序。这些影响来自不同的配置,因此每行给出各自的配置。

展示原因、修复及其效果

原因修复PR效果配置
在 decode worker 线程上同步提交 KV 读取使用 UCX scatter-gather 的 NIXL push;打包的 KV 行作为一个 NIXL region 发送NIXL push connector,#61121每 GPU 141K → 440K tokens/s;每用户 P90 约 40 → 159 tokens/sGB300,8P1D,并发 3,072
Gloo all-reduce 延迟随 rank 数量线性增长递归倍增 CPU all-reduce#61767,基于 #60267每步 DP 同步 10.8 → 1.5 ms;步耗时 16.10 → 13.15 msDEP32 decode
准入突发:单步最多准入 140 个请求每步最多 4 次新 KV 加载的可选上限#61725每 GPU 460K → 516K tokens/s;每用户 P90 109 → 153 tokens/sGB300,7P1D,并发 4,800,另含两项 CPU 修复
随 prompt 长度增长的准入工作将 prompt 作为单个 int32 缓冲区;跳过滑动窗口块表的空块;分块 prompt 拷贝 kernel#59908, #62702, #61724, #62698855K prompt:每次准入的 CPU 耗时 38.8 → 6.0 ms引擎微基准测试

低延迟:面向小批量的专用 decode 路径

我们还将低延迟 kernel 支持扩展到了 DeepSeek-V4.1-Flash(#61868 和 #61869),延续了上一篇文章中的工作。在真实 AgentX 会话中,专用 decode 路径在四块 B300 GPU 上为单个用户达到 826 P90 tokens/s,比标准 decode 路径(575)高 44%。

图 7:在四块 B300 GPU 上以 TP4 运行 SemiAnalysis AgentX,并发为 1、8 和 16,对比 InferenceX #4332 切换到专用 decode 路径前后的表现。

致谢

我们感谢 DeepSeek 开源并分享 DeepSeek-V4.1-Flash 及其优化 kernel,为本工作提供了基础,并感谢其发布 DeepInfer 及其性能结果,为我们提供了学习和对比的重要参考。我们也感谢 SemiAnalysis 提供 AgentX 基准平台以及所有帮助。

我们特别感谢来自 NVIDIA 的 Pei Li、Hanjie Qiu、Lisa Wang、Yaoyao Ding、Rohit Nagraj 和 Xin Li 在性能优化上的紧密合作、在 vLLM 和 Dynamo 上的持续支持,以及在 AgentX 提交方面的协助。我们也感谢来自 vLLM 社区 的 Canlin Guo 提供的宝贵 prefill 优化。

本工作由 Inferact 主导。

脚注

  1. DEPn 是数据并行注意力加上跨 n 块 GPU 的专家并行。Target forward 是主模型在每个 decode 步的完整前向,用于验证 draft token 并产生输出;draft forward 是 DSpark draft 模型的完整前向,为下一步提出 token。↩

  2. 在较早的构建上测得;不均衡成本是 DEP 规模的属性,而非 kernel 的属性。↩

来源:vLLM Blog · vllm.ai