SGLang 在 96 张 H100 上用 PD 分离和大规模专家并行复现 DeepSeek 推理性能
Blog Deploying DeepSeek with PD Disaggregation and Large-Scale Expert Parallelism on 96 H100 GPUs DeepSeek is a popular open-source large language model (LLM) praised for its strong performance. However, its large size and unique architecture, which uses Multi-head Latent Attention (MLA) and Mixtu... The SGLang Team May 5, 2025
SGLang 团队发布博客,介绍在 12 节点共 96 张 H100 上通过 prefill-decode 分离和大规模专家并行(EP)复现 DeepSeek 官方推理系统性能。
SGLang 团队公开了在 96 张 H100 上复现 DeepSeek 推理系统的并行设计与优化细节,本地部署成本约为官方 API 的五分之一。
DeepSeek 是一款广受欢迎的开源大型语言模型(LLM),以其强劲的性能备受赞誉。然而,其庞大的规模和独特的架构——采用多头潜在注意力(MLA)和专家混合(MoE)——需要一套先进的系统才能实现大规模高效服务。在这篇博客中,我们解释如何用 SGLang 匹配 DeepSeek 推理系统的性能。

我们的实现如上图所示,运行在 Atlas Cloud 的 12 个节点上,每个节点配备 8 块 H100 GPU。 它采用预填充-解码分离和大规模专家并行(EP),对于 2000 token 的输入序列,实现了每节点每秒 52.3k 输入 token 和每秒 22.3k 输出 token的速度。 据我们所知,这是首个在大规模下接近 DeepSeek 官方博客所报告吞吐量的开源实现。 通过本地部署这一实现,折算成本为每 100 万输出 token 0.20 美元,约为官方 DeepSeek Chat API 成本的五分之一。 与使用相同资源的普通张量并行相比,这一优化策略将输出吞吐量提升最高达 5 倍。 本博客深入探讨我们的并行设计、优化方法和结果。我们工作的所有组件完全开源,允许他人探索并在我们的成果之上继续构建。复现我们实验的说明可在此完整获取。
亮点
✅ SGLang 现已支持预填充-解码(PD)分离和大规模 EP,包括 DeepEP、DeepGEMM 和 EPLB 的全部功能。
✅ 借助这些新特性,我们团队使用 12 个节点(每个节点配备 8 块 H100 GPU)成功复现了 DeepSeek 的推理系统。总体而言,对于 2000 token 的输入序列,SGLang 实现了每节点每秒 52.3k 输入 token 和每秒 22.3k 输出 token 的吞吐量。
✅ 本博客解释了我们方法的技术细节,重点聚焦于效率优化、峰值内存占用降低和工作负载均衡。性能分析结果表明,我们的实现达到了与 DeepSeek 官方报告几乎相当的性能。
✅ 所有实验和代码完全开源,供社区访问和进一步开发。
大纲
并行设计
高效的并行对于管理 DeepSeek 架构的计算复杂度和内存需求至关重要。本节概述我们优化关键组件的方法:注意力层、稠密前馈网络(FFN)、稀疏 FFN 和语言模型(LM)头。每个组件都利用量身定制的并行策略来增强可扩展性、内存效率和性能。
注意力层
DeepSeek 采用多头潜在注意力(MLA)来有效建模输入序列中的复杂依赖关系。为了优化这一机制,我们实现了DP Attention,这是一种数据并行策略,可消除设备间的 KV 缓存重复,显著降低内存开销。该方法在 SGLang v0.4 中引入,并已扩展支持混合数据并行与张量并行,为高效处理小批量大小提供了灵活性。
稠密 FFN
尽管仅使用三个稠密 FFN 层,DeepSeek-V3 的计算仍可能显著增加峰值内存使用,若不小心管理,可能导致系统崩溃。为解决此问题,我们采用数据并行(DP)而非张量并行(TP),利用以下优势:
- 增强的可扩展性:在中间维度为 18,432 的情况下,高 TP 度(例如 TP32)会导致低效地分割成小单元段(例如 576 个单元),这些段不能被 128 整除——这是现代 GPU(如 H100)常见的对齐边界。这种不对齐会妨碍计算效率和内存利用率。DP 通过避免分割提供了更具可扩展性的解决方案,确保设备间工作负载均衡分布。
- 优化的内存效率:传统上,TP 随着工作节点规模增加而减少内存使用,但在 DP 注意力下这一优势减弱。在纯 TP 设置中,单层 Transformer 模型的内存需求随 DP 大小变化为:Memory=NparamTP+(1+k)Nhidden_state⋅DP 这里,Nhidden_state=ntoken×nhidden_size 是每个设备(DP rank)上隐藏状态的大小,Nparam=nintermediate_size×nhidden_size 是模型参数数量,k 是表示 CUDA Graph 复制带来的额外内存开销的系数。假设 DP=TP,当 TP=Nparam(1+k)Nhidden_state 时,此内存使用函数最小化。DeepSeek-V3 使用 18,432 的中间大小。在预填充阶段,CUDA Graph 通常被禁用,因此 k=0。然而,每个设备的 token 大小很容易超过 2,048,导致最优 TP 大小为 3 或更小。在解码阶段,实际配置可能使用每个设备 128 个 token 并设置 k=3。在这种情况下,内存最优 TP 大小为 6。在两个阶段中,较低的 TP 度都能最小化每个设备的内存使用。因此,与仅依赖 TP 相比,DP 可能提供更具内存效率的扩展方法。
- 最小化通信开销:在纯 TP 中,每个 FFN 需要两次 all-reduce 操作,导致大量通信开销。通过利用 DP,我们将此过程优化为在前一个注意力层之后进行一次 reduce-scatter,并在下一个之前进行一次 all-gather,将通信成本降低 50%。此外,当注意力也在纯 DP 下计算时,设备间通信完全消除,显著提高整体效率。
DP 稠密 FFN 与 DP 注意力的集成如下图所示。用户可以通过设置 --moe-dense-tp-size=1 来启用此功能。

稀疏 FFN
在 DeepSeek-V3 的混合专家(MoE)架构中,稀疏 FFN 需要大量的专家权重,造成了显著的内存瓶颈。为了解决这个问题,我们实现了专家并行(EP),将专家权重分布到多个设备上。这种方法在保持高性能的同时有效扩展了内存容量,不过也引入了诸如不规则的全对全通信和工作负载不均衡等挑战。
上方右图展示了我们使用 DeepEP 框架的 EP 实现,关于我们 EP 设计和优化的更多细节将在以下章节中提供。
LM Head
LM Head 在大词表上计算输出概率,这是一项资源密集型操作,传统上通过词表并行来处理,从 TP 组中聚合 token logits。为了提升可扩展性和效率,我们采用了数据并行(DP),与我们的稠密 FFN 策略一致。这减少了内存开销并简化了设备间的通信,提供了更精简的解决方案。
Prefill 与 Decode 分离
LLM 推理包含两个不同的阶段:Prefill 和 Decode。Prefill 阶段是计算密集型的,处理整个输入序列;而 Decode 阶段是内存密集型的,管理用于 token 生成的键值(KV)缓存。传统上,这两个阶段在统一引擎中处理,prefill 和 decode 批次的合并调度引入了低效问题。为了解决这些挑战,我们在 SGLang 中引入了 Prefill 与 Decode(PD)分离。
统一调度的问题
传统的统一引擎将 prefill 和 decode 批次一起处理,导致了三个显著问题:
- Prefill 中断:新到达的 prefill 批次频繁中断正在进行的 decode 批次,导致 token 生成出现严重延迟。
- DP 注意力不均衡:在 DP 注意力中,一个 DP worker 可能处理 prefill 批次,而另一个同时处理 decode 批次,导致 decode 延迟增加。
- 与 DeepEP 不兼容:正如我们将在后续章节中讨论的,DeepEP 对 prefill 和 decode 执行不同的分发模式,使得统一调度与 DeepEP 不兼容。
PD 分离通过将两个阶段分开解决了这些问题,使每个阶段都能进行针对性的优化。
实现细节
SGLang 中的 PD 分离设计如下图所示,在 Prefill 服务器和 Decode 服务器之间交错执行:

收到输入请求后,工作流程如下:
- Prefill 服务器和 Decode 服务器通过握手配对,分别建立本地发送端和接收端。
- Decode 服务器预分配 KV 缓存,通知 Prefill 服务器开始模型前向传播并计算 KV 缓存。
- 计算完成后,数据传输到 Decode 服务器,由其处理迭代式 token 生成。
这种分离确保每个阶段在最优条件下运行,最大化 GPU 资源利用率。为了进一步提升性能,我们的实现还包含:
- 非阻塞传输:数据发送和接收操作在后台线程中运行,保持调度器的事件循环不中断。
- 基于 RDMA 的传输:远程直接内存访问(RDMA)利用队列对进行连接,并使用分散-聚集元素(SGE)来高效传输非连续内存块。
- 灵活的 API 集成:SGLang 提供可适配的 API,可集成 Mooncake 和 NIXL 等高性能 RDMA 库,从而简化数据传输。
更多细节可在我们的设计文档中找到。
大规模专家并行
使用 DeepEP 的专家并行
DeepEP 由 DeepSeek 团队实现,是一个旨在简化 MoE 模型中 EP 的通信库。它解决了跨多个 GPU 将 token 高效路由到特定专家的挑战。通过提供优化的通信内核,DeepEP 降低了延迟并提升了吞吐量,使其非常适合大规模推理任务。
DeepEP 提供两种专门的 dispatch 模式,以应对不同的工作负载需求:
- Normal Dispatch:针对处理长输入序列(例如 prefill 阶段)进行了优化,此模式优先考虑最大计算吞吐量。然而,它会生成与 CUDA Graph 不兼容的符号形状,使其在 decode 阶段效果较差,因为在该阶段内核启动开销成为显著瓶颈。
- Low-Latency Dispatch:专为 decode 阶段生成输出 token 而定制,此模式优先考虑最小延迟以确保实时性能。它支持 CUDA Graph,但需要预分配固定内存大小。如果内存需求超过此预分配值,则会发生运行时错误。
在 SGLang 中,DeepEP 的集成提供了自动模式,可根据工作负载在这两种 dispatch 模式之间动态选择。然而,在没有 PD 分离的情况下,自动模式面临一个限制:它无法在同一通信组内同时支持 normal dispatch(用于 prefill)和 low-latency dispatch(用于 decode)。这一限制阻碍了其与 DP attention 的兼容性,而 DP attention 对于内存高效推理至关重要。每种模式的兼容性如下表所示:
| 模式 | 长输入 | 长输出 | DP Attention | CUDA Graph |
|---|---|---|---|---|
| Normal | ✅ | ❌ | ✅ | ❌ |
| Low-Latency | ❌ | ✅ | ✅ | ✅ |
| Auto | ✅ | ✅ | ❌ | ✅ |
PD 分离通过将 prefill 和 decode 阶段分开来解决此问题,允许在 DP attention 下,prefill 阶段使用 normal dispatch,decode 阶段使用 low-latency dispatch。这种集成通过使 dispatch 模式与每个阶段的具体需求相匹配,优化了资源利用率并提升了整体性能。
DeepGEMM 集成
DeepGEMM 是 DeepSeek 团队开发的另一个高效库,专门用于优化 MoE 模型中的计算。它提供两个专门函数来处理与 MoE 相关的矩阵乘法(Grouped GEMMs),每个函数针对推理过程的不同阶段量身定制。
- Grouped GEMMs(连续布局): 此内核专为动态输入形状设计,非常适合 MoE 推理的 prefill 阶段。它处理不同专家的数据连续拼接的输入,从而灵活处理各种输入大小。
- 分组 GEMM(掩码布局): 该内核假定输入形状固定,并使用掩码张量仅计算输入的有效部分。它与 CUDA Graph 兼容,后者可优化内核启动,因此非常适合对降低开销至关重要的解码阶段。
DeepGEMM 与 DeepEP 的调度模式无缝集成:
- 对于连续布局内核,它在预填充阶段与普通调度配合使用,需要额外一步。由于普通调度输出的是符号形状,需要进行置换以将输出转换为内核所期望的连续格式。我们参考了 LightLLM 项目,并实现了一个自定义 Triton 内核以实现高效置换。该内核确保普通调度的输出被正确重排,从而能够与连续 GEMM 内核顺畅集成。
- 掩码布局内核与 DeepEP 的低延迟调度无缝配对,因为两者都针对解码阶段进行了优化并支持 CUDA Graph。
SGLang 还在张量并行下为 MoE 计算集成了 DeepGEMM。此外,DeepGEMM 提供了一个高效的通用 GeMM 内核,可通过将环境变量 SGL_ENABLE_JIT_DEEPGEMM 设置为 1 在 SGLang 中激活,从而为非 MoE 操作提供更高的计算效率。
双批次重叠
在多节点环境中,有限的通信带宽会显著增加整体延迟。为应对这一挑战,我们遵循 DeepSeek 的系统设计 实现了双批次重叠(TBO)。TBO 将单个批次拆分为两个微批次,使计算和通信能够重叠,同时通过将有效批次大小减半来降低峰值内存使用。然而,将 TBO 付诸实践会带来具体的实现困难。
实现挑战
尽管 DeepSeek 发布了 TBO 的设计框架,但在实现上仍有两个小挑战。
- 代码复杂性:直接编写 TBO 可能导致管理多个微批次的逻辑重复。这增加了代码库的复杂性,使其更难维护且容易出错,尤其是随着微批次数量或重叠场景的增加。
- 预填充阶段的同步问题:在 DeepEP 中的普通调度阻塞 CPU 时,实现计算与通信之间的有效重叠需要考虑这一点。这种阻塞行为可能会使流水线停滞,导致 GPU 空闲,并削弱 TBO 的性能优势。
用于简洁实现的抽象
为了创建更易维护和可复用的代码库,我们使用由操作和让出点组成的抽象层。这种方法简化了开发,使我们能够像处理单个微批次一样编写代码,同时通过插入让出点来策略性地暂停执行,让其他微批次继续推进。它消除了代码重复,减少了对变量后缀的潜在需求,并高效处理了某些执行在某一层结束时完成而其他执行尚未完成的情况。此外,它还能以极少的代码改动轻松适应不同的重叠区域选择或未来增强,例如三批次重叠。下面是对这种方法的简要演示:
operations = [
self._forward_attn,
YieldOperation(), # Pause execution for other micro-batches
self._forward_dispatch,
self._forward_mlp,
YieldOperation(), # Another pause point
self._forward_combine,
]
# Process a single micro-batch without duplicating code
def _forward_attn(self, state):
state.hidden_states = self.self_attn(state.hidden_states, ...)
预填充重叠实现
我们在预填充阶段优化了启动顺序,以避免 DeepEP 中 dispatch 操作导致的 CPU 阻塞,即使我们使用的是其异步模式。具体来说:
- dispatch 操作会阻塞 CPU,直到 GPU 从其他 rank 接收到元数据,以便分配正确大小的张量。
- 如果实现不当,在此期间计算流将处于空闲状态,因为没有计算任务提交给 GPU。
为了优化,我们优先在启动会阻塞 CPU 的通信之前,将计算任务提交给 GPU。这确保了 GPU 在通信期间保持活跃。如下图所示,采用正确启动顺序的 TBO(以粗体边框标示)避免了由 CPU 阻塞操作(即普通 dispatch)引起的气泡。

专家并行负载均衡器
在 MoE 模型中,EP 常常导致 GPU 之间的工作负载分布不均。这种不均衡迫使系统等待最慢的 GPU 计算或通信,浪费计算周期,并因专家激活而增加内存使用。随着 GPU 数量(EP 规模)的增加,不均衡问题变得更加严重。
为了解决这个问题,DeepSeek 开发了 专家并行负载均衡器(EPLB)。EPLB 以专家分布统计作为输入,计算最优的专家排列以最小化不均衡。用户可以分配冗余专家(例如额外 32 个专家),与原有的 256 个专家结合后,形成一个 288 个专家的池。这个池允许 EPLB 策略性地放置或复制专家——例如,将最常用的专家复制多份,或将使用频率中等的专家与很少使用的专家分组到单个 GPU 上。
除了平衡工作负载,EPLB 在并行设计上提供了更大的灵活性。使用原有的 256 个专家时,并行规模被限制为 2 的幂。EPLB 使用 288 个专家,支持更多样化的配置,例如并行规模为 12 或 72。
在下图中,我们通过模拟展示了规模和 EPLB 算法对不均衡问题的影响。我们计算 GPU 均衡度,即 MoE 层在 GPU 之间的平均计算时间与最大计算时间的比值,并使用 GPU 的 token 数量来估算其计算时间。可以看出,随着系统按节点数量扩展,利用率下降,而启用 EPLB 显著提高了利用率。

面向真实场景服务的 EPLB
要使 EPLB 有效,输入分布必须与实际服务负载紧密匹配。有两种策略可以增强这种匹配:
- 增大批次大小:更大的批次减少了专家使用中的随机波动,从而改善均衡,这可以通过扩展集群或使用多 Token 预测(MTP)等技术来实现。
- 周期性重新均衡:定期更新专家排列利用了时间局部性,但需要高效地重新加载专家。这要求最小化专家重新加载操作的成本。
即使使用 EPLB,一些不均衡也是不可避免的,因此进一步优化是一个有价值的未来方向。
重新均衡的实现
SGLang 分三个阶段实现专家重新均衡,以确保效率和最小干扰:
- 系统加载阶段:权重可选地从磁盘预加载到主内存以加快重新均衡,或通过内存映射(mmap)保留在磁盘上以减少内存使用。
- 重平衡准备阶段:所需权重在后台异步传输到设备内存,利用空闲的 DMA 硬件引擎,不中断正在进行的 GPU 操作。
- 重平衡执行阶段:通过设备到设备的复制来更新权重。此步骤可通过物理内存重绑定技术进一步优化。
这种分阶段的方法确保重平衡既高效又无干扰,在更新期间保持系统性能。
评估
端到端性能
实验设置
我们在一个由 12 个节点组成的集群上,使用 DeepSeek-V3 评估了 SGLang 不同配置的端到端性能,这些节点通过 InfiniBand 连接,每个节点配备 8 块 H100 GPU。本次评估展示了我们先进优化技术所带来的吞吐量提升。我们比较了以下四种设置:
- 采用 TP16 x 6 的 SGLang:每两个节点配对一个独立组,以 TP 大小为 16 和 DP 注意力运行 DeepSeek-V3 推理。
- 采用 PD 分离的 SGLang:此版本结合了 PD 分离和完整的 EP 优化。对于 EPLB,由于无法获得实时服务统计信息,我们采用与输入/输出数据匹配的分布。
- 采用 PD 分离和模拟 MTP 的 SGLang:为了模拟 MTP 的效果,我们首先将批大小加倍,并将键值 KV 缓存长度减半,以保持 GroupedGeMM 计算和内存访问的工作负载不变。此外,我们在真实注意力计算之后插入虚拟内核,以确保注意力阶段耗时与 DeepSeek 的 profile 一致,准确反映 MTP 注意力机制造成的减速。我们保守假设 MTP 下的接受率为 70%。
- DeepSeek Profile 结果:吞吐量估算值来自 DeepSeek 的官方 profiling 数据。
Prefill 和 Decode 阶段的性能分析
为了适应不同的工作负载需求,我们独立评估了 prefill(P)和 decode(D)阶段,假设未测试阶段拥有无限资源,以隔离并最大化受测节点的负载——这与 DeepSeek 使用的设置一致。结果总结如下:
- Prefill 阶段:在 4 个节点(4×8×H100,EP32)上,对于 1K、2K 和 4K 的提示长度,系统分别实现了每节点 57,674、54,543 和 50,302 tokens/秒的吞吐量。如下方柱状图所示,这相比 TP16 基线最高提升了 3.3 倍,主要归功于优化的 GroupedGeMM 内核(DeepGEMM)和双批次重叠。假设工作负载完全均衡,我们系统的吞吐量与 DeepSeek 官方 profile 的差距在 5.6% 以内。
- Decode 阶段:在 9 个节点(9×8×H100,EP72;为 DeepSeek 规模的一半)上评估,对于 2K 输入,系统实现了每节点 22,282 tokens/秒——相比 TP16 基线提升了 5.2 倍。在模拟 MTP 条件下——注意力内核被有意放慢以反映真实延迟——系统在 4K 输入下仍保持了每节点 17,373 tokens/秒的高吞吐量,仅比 DeepSeek 官方 profile 低 6.6%。如右图所示,这些性能提升主要归功于 EP 带来的 4 倍更大的批大小,通过显著降低模型权重的每 GPU 内存消耗来增强可扩展性。

Profile 结果
本节将 SGLang 的性能与 DeepSeek 的推理系统进行比较,尽可能使我们的实验设置贴近 DeepSeek 的生产环境。我们分析了整体吞吐量和详细的内核分解,并以 DeepSeek 的博客和公开资料数据为基准进行对比。
整体吞吐量
对于 prefill,我们测试了每设备 16,384 个 token、输入长度为 4,096 的场景。由于 DeepSeek 的专家分布存在不确定性,我们评估了两种情况:一种是默认专家分布,另一种是模拟完美 EPLB(遵循组限制路由语义的随机专家选择)作为性能上限。
结果如下所示:
| DeepSeek 博客(不含缓存命中) | DeepSeek 公开资料 | SGLang(默认) | SGLang + 模拟完美 EPLB | |
|---|---|---|---|---|
| 批大小 | N/A | 16,384 | 16,384 | 16,384 |
| 输入长度 | N/A | 4,096 | 4,096 | 4,096 |
| 吞吐量(每节点) | 32,206 | 62,713 | 50,302 | 59,337 |
DeepSeek 的公开资料报告的吞吐量大约是其生产环境的两倍。SGLang 在默认专家不均衡情况下比 DeepSeek 的公开资料慢 20%,而模拟完美 EPLB 的情况将差距缩小到 6%。
对于 decode,结果如下所示:
| DeepSeek 博客 | DeepSeek 公开资料 | SGLang(默认) | SGLang + 模拟 MTP(慢注意力) | |
|---|---|---|---|---|
| 批大小 | N/A | 128 | 256 | 128 |
| KV 缓存长度 | 4,989 | 4,096 | 2,000 | 4,000 |
| 节点数 | 18 | 16 | 9 | 9 |
| 吞吐量(每节点) | 14,800 | 18,598 | 22,282 | 17,373 |
使用 DeepSeek 一半的节点,SGLang 在模拟 MTP 下仅比 DeepSeek 的公开资料略慢。在更高的批大小设置下(256 个序列,2,000 输入长度),SGLang 达到每节点每秒 22,282 个 token,展现出强大的可扩展性。
详细分解
下图分解了 prefill 的内核执行时间,包括作为理论上限的单元测试结果:

- 默认 EPLB:与 DeepSeek 的公开资料相比,通信内核执行时间更长且方差更高,可能是由于更大的专家不均衡。这导致计算流气泡延长,拖慢整体性能。
- 模拟完美 EPLB:此设置与 DeepSeek 的公开资料更为接近,但仍存在差异,表明有潜在的优化空间。
- 与单元测试的对比:DeepSeek 和 SGLang 的通信时间都慢于单元测试结果,而后者在禁用 TBO 时可以实现,这揭示了如果通信成为瓶颈时的潜在优化方向。
SGLang 的 decode 内核分解与 DeepSeek 的密切吻合,如下所示:

关键观察包括:
- Combine 时间差异:SGLang 的 combine 操作似乎比 DeepSeek 慢 2 倍,原因是注意力计算更短,导致通信内核忙等待。在模拟慢注意力实验中,combine 时间与 DeepSeek 匹配,证实了这一假设。
- MoE 性能:SGLang 的 MoE 内核慢 25%,可能是因为 DeepSeek 的 18 个节点(相比我们的 9 个)更高效地分布专家,减少了 GEMM 操作的内存访问开销。
- Dispatch 优化潜力:DeepSeek 和 SGLang 的 dispatch 时间都约为每层 0.17ms,但使用 DeepEP 的单元测试揭示了占用 SM 的 0.06ms 潜力。目前,dispatch 花费大量时间忙等待数据。在发送/接收操作之间插入慢速 dummy 内核可将 dispatch 时间降至 0.09ms,而使用单元测试数据的在途时长分析表明还有进一步改进的可能。
尽管仍有小幅优化空间——主要是在“其他内核”下的内核融合方面——SGLang 的解码性能已基本与 DeepSeek 持平,下一步的重点是预填充优化。
消融研究:双批次重叠
批次大小与注意力时间的影响
本节研究 TBO 在不同批次大小和模拟 MTP 场景下的性能表现。

从吞吐量对比和内存使用优化可以看出,TBO 在预填充阶段带来两项显著收益:
- 支持更大的批次大小:在默认配置下,每台设备最多处理 8,192 个 token,达到 16,384 个 token 时便会遇到内存不足(OOM)错误。TBO 通过优化输入 token 的内存使用缓解了这一问题,使每台设备能够以高达 16,384 个 token 的批次进行推理。将所有其他配置调至最优后,与 TBO 标志相比,性能进一步提升至 40.5% 的增长。
- 提升吞吐量:通过将计算(例如注意力与 MLP 阶段)与通信(例如 DeepEP Combine 和 Dispatch)重叠,即使每台设备处理的 token 数量相同,TBO 相比默认配置也能实现 27% 至 35% 的吞吐量提升。
TBO 在解码阶段的影响因场景而异,其性能与批次大小和注意力处理时间相关:
- 真实测试用例:实际场景中的加速取决于批次大小是否超过 64 至 128 个 token 之间的阈值。低于该阈值时,TBO 带来的收益微乎其微甚至为负(例如每台设备 32 个 token 时为 -27%),因为较小的解码批次会降低内核效率。在 256 个 token 时加速达到 25.5%,性能为每秒 22,310 个 token。
- 模拟 MTP 场景:在模拟 MTP 场景中,当处理 128 个请求以在每个解码步骤生成 256 个 token 时,TBO 提供的加速最为显著。这是由于注意力处理时间延长,使计算(例如 DP Attention 层)与 DeepEP 通信开销(例如 combine 和 dispatch 步骤)得以重叠。评估显示,在每台设备 128 个序列时加速达 35%,吞吐量为每秒 17,552 个 token,而未使用 TBO 时为 12,929。
详细分解
我们评估了三种预填充场景:每批次 16k token 的 TBO、8k token 的 TBO,以及 8k token 的无 TBO。下图揭示了关键洞察:
- TBO 效率:对比 8k 的两种情况,TBO 如预期那样通过重叠计算与通信提升了整体效率。
- 批次大小的影响:使用 TBO 时将批次大小从 16k 降至 8k 会导致轻微变慢,反映出较小批次下内核效率的下降。
- 内核性能:有趣的是,无 TBO 的 8k 情况在单内核速度上优于 TBO 的 16k 情况,尽管两者内核的有效批次大小均为 8k。这可能源于 TBO 下流式多处理器(SM)数量减少、重叠期间潜在的邻居干扰效应,或计算与通信之间的内核不兼容。这些发现为 SGLang 指明了未来的优化方向。

对于解码阶段,我们分析了三种配置:批次大小为 256 的 TBO、256 的无 TBO,以及 128 的无 TBO。时间分解如下所示:
- TBO 与 No-TBO(批大小 256):不使用 TBO 时,由于缺乏重叠,通信时间显著增加。然而,计算内核,尤其是 GEMM,受益于更大的有效批大小,从而执行更快。
- TBO(256)与 No-TBO(128):在相同内核批大小的情况下进行比较,只有非重叠通信在 no-TBO 设置中变慢,而计算保持一致。与 prefill 不同,decode 通信内核要么完全利用 SM(在发送/接收期间),要么完全不利用(在 inflight 等待期间),从而避免与计算内核的资源争用。

消融研究:EPLB
本节通过整体吞吐量分析和详细案例研究,评估 EPLB 对系统性能的影响。鉴于 EPLB 对生产环境中的工作负载分布和分布偏移较为敏感,我们聚焦于定性和可泛化的洞见,而非需要生产数据的真实性能。
整体结果
下图展示了 EPLB 在大规模设置中对吞吐量的影响。正如预期,EPLB 带来了 1.49 倍(prefill)和 2.54 倍(decode)的显著加速,这得益于其缓解 GPU 间工作负载不均衡的能力。随着 rank 数量的扩展,不均衡会加剧,而 EPLB 在我们的大规模实验中有效解决了这一问题,从而带来显著的吞吐量提升。

案例研究:工作负载不均衡与整体吞吐量
为了探究工作负载不均衡与吞吐量之间的关系,我们使用一个 decode 实验进行了案例研究,输入 token 为 1800,输出 token 为 100,批大小为 256。吞吐量和均衡度(各专家平均 token 数除以最大 token 数)随解码步数绘制成图:

结果揭示了均衡度与吞吐量之间的强相关性,强调了保持高均衡度以实现最优性能的重要性。
案例研究:专家分布统计
下图展示了 prefill 和 decode 样本数据的专家分布统计:

关键观察包括:
- 专家使用不均衡:大多数专家很少被使用,而一小部分专家被大量使用,凸显了 MoE 模型中固有的不均衡。
- Prefill 与 Decode 的差异:尽管 prefill 和 decode 分布有相似之处,但也存在显著差异。这支持使用 PD 分离,从而能够为每个阶段设置不同的专家放置,优化性能。
这些发现凸显了 EPLB 在解决工作负载不均衡方面的作用,以及根据阶段特定需求定制专家放置的价值。
工具包
一次性张量
由于持久对象引用,PyTorch 中的内存管理可能颇具挑战,尤其是在 CUDA 内存是稀缺资源的 GPU 密集型工作流中。考虑以下示例:
def ffn(hidden_state: torch.Tensor, linear1: nn.Linear, linear2: nn.Linear):
intermediate_state = linear1(hidden_state)
del hidden_state # Attempt to free memory, but no effect due to external reference
return linear2(nn.ReLU(intermediate_state))
hidden_state = ffn(hidden_state, linear1, linear2)
在这段代码中,del hidden_state 旨在在计算完 intermediate_state 后释放 hidden_state 占用的内存。然而,由于 hidden_state 仍在函数外部被引用,del 操作没有效果。这增加了峰值内存使用量,可能导致性能下降或内存不足错误。
SGLang 通过 DisposableTensor 类解决了这个问题,它是 torch.Tensor 的子类,引入了 dispose() 方法,可以显式且立即释放张量的内存,绕过 Python 的引用计数限制。其工作原理如下:
def ffn(hidden_state: torch.Tensor, linear1: nn.Linear, linear2: nn.Linear):
intermediate_state = linear1(hidden_state)
hidden_state.dispose() # Immediately releases CUDA memory
return linear2(nn.ReLU(intermediate_state))
# Wrap the tensor in DisposableTensor
hidden_state = DisposableTensor(hidden_state)
hidden_state = ffn(hidden_state, linear1, linear2)
通过将 hidden_state 包装在 DisposableTensor 中,并在不再需要时调用 dispose(),CUDA 内存会立即释放。这确保了张量在计算中的角色完成后立即释放内存,从而降低峰值内存使用并提高整体效率。
专家工作负载提取与模拟
SGLang 还包含一套用于分析和模拟 MoE 模型中专家工作负载分布的工具集。此功能使用户能够:
- 导出专家工作负载统计信息:提取累积统计信息或每批次工作负载数据。累积统计信息支持 EPLB 管理器进行实时优化,而每批次数据则为分析和模拟提供细粒度洞察。
- 模拟专家利用率:在各种配置下模拟专家平衡,无需昂贵的硬件或反复试验。例如,用户可以从适度的设置(例如 2x8xH100 或 8xH200)收集工作负载数据,并模拟大规模 22 节点部署的性能。
此模拟能力允许用户评估重新平衡频率、节点数量或批次大小等因素如何影响系统性能。这是一种在扩大规模之前微调配置的经济高效的方法。
局限性与未来工作
虽然我们为 DeepSeek-V3 推理实现的 SGLang 展示了显著的吞吐量改进,但仍存在一些局限性和未来增强的领域:
- 延迟优化:当前对吞吐量的关注使得首令牌时间(TTFT)为 2–5 秒,令牌间延迟(ITL)约为 100ms,需要进一步优化以满足实时用例。
- 序列长度限制:由于使用 96 个 GPU,仅限于较短的序列。扩展 GPU 资源将支持更长的序列,这对特定应用至关重要。
- 多令牌预测(MTP)集成:SGLang 支持 MTP,但缺乏与 DP 注意力的完全集成,降低了混合并行配置的效率。
- EPLB 分布:本博客中的实验使用了专家并行负载均衡器(EPLB)的分布内数据,这可能无法反映现实世界的变异性。未来工作应在分布偏移时实验性能。
- 灵活的张量并行(TP)大小:对于 DeepSeek-V3,密集 FFN 的内存最优 TP 大小较小但大于 1。目前,SGLang 仅支持纯 TP 或 DP,导致内存使用次优。需要灵活的 TP 选项。
- Blackwell 支持:目前,我们的实现仅支持 NVIDIA Hopper 架构。我们正在积极努力将兼容性扩展到下一代 Blackwell 架构。如果您有兴趣支持或赞助此开发,欢迎联系 lmsys.org@gmail.com。
结论
通过利用 PD 分离、EP 以及精心设计的并行方案,我们在 SGLang 中复现了 DeepSeek 的推理框架,并取得了卓越的性能。我们的开源工作——实现每秒 52.3k 输入令牌和每秒 22.3k 输出令牌——展示了 SGLang 在大规模 LLM 推理中的强大能力。我们邀请社区探索、复现并扩展这项工作,以推动高效 AI 部署的边界。
致谢
我们衷心感谢以下团队和合作者:
- SGLang 核心团队与社区贡献者 — Jingyi Chen、Cheng Wan、Liangsheng Yin、Baizhou Zhang、Ke Bao、Jiexin Liang、Xiaoyu Zhang、Yanbo Yang、Fan Yin、Chao Wang、Laixin Xie、Runkai Tao、Yuhong Guo、Kaihong Zhang、Lei Yu、Yu-Hsuan Tseng、Qilin Tian、Peng Zhang、Yi Zhang、Yineng Zhang、Byron Hsu 以及许多其他人。
- Atlas Cloud 团队 — Jerry Tang、Wei Xu、Simon Xue、Harry He、Eva Ma 及同事 — 提供 96 卡 NVIDIA H100 集群并给予及时的工程支持。
- NVIDIA 解决方案架构师团队 — Xuting Zhou、Jinyan Chen 及同事 — 在专家并行的无缝集成方面所做的工作。
- NVIDIA 企业产品团队 — Trevor Morris、Elfie Guo、Kaixi Hou、Kushan Ahmadian 及同事 — 优化 DeepSeek R1 内核。
- LinkedIn 团队 — Biao He、Qingquan Song、Chunan Zeng、Yun Dai、Yubo Wang 及同事 — 优化 Flash-Attention 3 后端。
- Mooncake 团队 — Shangming Cai、Teng Ma、Mingxing Zhang 及同事 — 在 SGLang 中 PD 分离方面的协作。
- FlashInfer 团队 — Zihao Ye、Yong Wu、Yaxing Cai — 额外的 DeepSeek R1 内核优化。
- Dynamo 团队 - Kyle Kranen、Vikram Sharma Mailthody 及同事 - 为 SGLang 中 PD 分离提供额外支持。
感谢大家的宝贵支持与协作。
附录
相关 PR:#1970 #2925 #4068 #4165 #4232 #4390 #4435 #4521 #4654 #4767 #4770 #4836 #4880 #4957 #5068 #5085 #5295 #5415 #5432 #5435 #5530 #5558 #5561 #5626 #5657 #5805 #5819 #5890 DeepEP#142
来源:LMSYS:Blog(Chatbot Arena 团队) · lmsys.org