使用 vLLM 在 NVIDIA B300 GPU 上部署 GLM-5.2

使用 vLLM 在 NVIDIA B300 GPU 上部署 GLM-5.2

vLLM 已成功在 24 块 NVIDIA B300 GPU(三台 8-GPU 服务器)上通过解耦的 Prefill/Decode (P/D) 拓扑部署了 GLM-5.2-NVFP4。通过优化服务等级协议 (SLA) 合规性而非峰值吞吐量,团队将平均每个输出 Token 的时间 (TPOT) 从近 40 ms 降低到了 17 ms,在 16K 到 256K token 的上下文长度范围内,达到了平均 TTFT ≤ 2.5 s 和平均 TPOT ≤ 20 ms 的生产目标。

优先考虑 SLA 合规性而非峰值吞吐量

在同机部署中,prefill 分块可能会与 decode batch 交织,导致长提示词增加现有请求的 token 间延迟。vLLM 利用 P/D 解耦技术将 prefill 工作从 decode 关键路径中移除,确保 TPOT 仅由 decode batch 的组成决定。

本次部署的生产需求包括:

  • 上下文长度: 16K–256K tokens。
  • 平均 TTFT (首个 Token 延迟): ≤ 2.5 s。
  • 平均 TPOT (每个输出 Token 的时间): ≤ 20 ms (约 50 tokens/s)。
  • 吞吐量: 仅在满足上述两个延迟约束后才进行最大化。

GLM-5.2 是一个拥有 744B 参数的 MoE 模型,具有 40B 激活参数,采用了 DSA 稀疏注意力机制和 MTP 投机解码。

优化 Decode 性能

初始配置在 16K-token 输入下的平均 TPOT 接近 40 ms。为了将其控制在 SLA 限制内,实施了以下优化:

针对混合 Batch 的投机填充 (Speculative Padding)

性能分析显示,当一个请求从 Prefill 节点转移到 Decode 节点时,其第一个 Decode 步骤仅需要一个 token,而使用多 Token 预测 (MTP) 的现有请求则需要 1 + N 个 token。这种不匹配创建了一个混合 batch,迫使系统从快速的 CUDA Graph 路径回退到开销巨大的分段执行或 eager 执行。

为了解决这个问题,vLLM 在 Decode 端实现了投机填充,在请求的第一步添加虚拟 token 以匹配 1 + N 的形状。这项优化(已合并至 PR #45237)将平均 TPOT 从 40 ms 降低到了 22 ms。

Model Runner V2 (MRV2)

启用 Model Runner V2 (VLLM_USE_V2_MODEL_RUNNER=1) 使 TPOT 降低了 11%。关键改进包括:

  • Warmup Kernels: 将 GLM-5.2 DSA indexer prefill-metadata kernel 添加到启动预热中 (PR #47285),以防止冷启动延迟峰值。
  • Local Argmax Reduction: 多 GPU MTP 现在使用本地 argmax reduction (PR #46448),将 TP 通信量从全词表 logits 降低到约 2 × TP 大小。
  • 动态投机长度: 全量 CUDA Graphs 现在支持动态投机长度 (PR #45953),减少了 eager 回退。

通信与 Graph 配置

  • All-to-All 后端: 使用 flashinfer_nvlink_two_sided 后端取代默认的 EP 后端,使 TPOT 降低了 4%。
  • CUDA Graph 模式: Decode 实例使用 FULL_DECODE_ONLY 模式并配合 --max-num-batched-tokens 1024,在减少启动编译时间的同时提供了完整的 graph 覆盖。
  • MTP 配置: Decode 端使用 num_speculative_tokens=3 以摊销执行成本,而 Prefill 端使用 num_speculative_tokens=1 以优先考虑快速的 KV cache 移交。

Prefill 并行度与容量权衡

在评估 Prefill 的并行策略时,团队比较了 TGS (每 GPU 吞吐量)。虽然 TP1 DP4 EP 并非每个 GPU 最有效的配置(TP1 DP2 EP 的效率高出 8%),但为了确保 GLM-5.2 的 1M-token 上下文能力有足够的 KV-cache 容量,最终选择了 TP1 DP4 EP。

稳定 MTP 接受率

为了确保投机解码在高并发下保持有效,vLLM 实现了 IndexerCache (PR #44420)。该机制复用 DSA indexer 产生的 Top-K 稀疏索引,防止系统为每个 MTP 草稿步骤重新运行 indexer。

其他稳定性修复包括:

  • Indexer 初始化: 改进了跳过 Top-K 层时的归一化循环和初始化 (PR #45895)。
  • 共享 Index Buffer: 优化了批量请求的布局,仅保留最终查询 token 的索引 (PR #47238)。
  • Post-Final-Norm 隐藏状态: 确保 MTP 循环复用 post-final-norm 隐藏状态 (PR #47448)。

在 AIME 2025 (86.67)、GPQA (92.89) 和 LongBench V2 (64.01) 上的准确性验证确认了这些优化并未降低输出质量。

生产可观测性与稳定性

监控解耦的 P/D 部署需要跟踪两个资源池的指标。关键指标包括每个池的 TTFT/TPOT 分位数、MTP 接受率以及 KV 传输延迟。

在长期稳定性测试期间,团队发现了一个主机内存泄漏问题,即 vLLM 进程的 RSS 随时间线性增长。根本原因是 SingleTypeKVCacheManager.new_block_ids 中的门控机制不一致 (PR #35219),它记录了非 Mamba 模型的 block 分配但从未释放它们。通过在每个调度步骤无条件调用 take_new_block_ids() 解决了此问题。

部署方案

硬件与拓扑

  • 硬件: 3 × 8 B300 GPU (共 24 块)。
  • 模型: GLM-5.2-NVFP4。
  • 拓扑: 4 个 Prefill 节点 (TP1 DP4 EP, 16 GPUs) 和 1 个 Decode 节点 (TP1 DP8 EP, 8 GPUs)。
  • KV 传输: NIXL。

配置命令

Prefill 节点:

export VLLM_USE_V2_MODEL_RUNNER=1
vllm serve /mnt/model/glm/GLM-5.2-NVFP4 --trust-remote-code --kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_producer"}' --chat-template-content-format=string -ep -tp 1 -dp 4 --tool-call-parser glm47 --enable-auto-tool-choice --reasoning-parser glm45 --gpu-memory-utilization 0.92 --enable-prompt-tokens-details --speculative-config='{"method":"mtp","num_speculative_tokens":1}' --shutdown-timeout 300 --fingerprint-mode=none

Decode 节点:

export VLLM_USE_V2_MODEL_RUNNER=1
vllm serve /mnt/model/glm/GLM-5.2-NVFP4 --trust-remote-code --chat-template-content-format=string --kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_consumer"}' --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' --max-num-batched-tokens 1024 -ep -tp 1 -dp 8 --tool-call-parser glm47 --enable-auto-tool-choice --reasoning-parser glm45 --gpu-memory-utilization 0.90 --enable-prompt-tokens-details --all2all-backend=flashinfer_nvlink_two_sided --speculative-config='{"method":"mtp","num_speculative_tokens":3}' --shutdown-timeout 300 --fingerprint-mode=none

Sources