vLLM v0.32.0 GLM-5.3 服务:在 16 块 H200 上实现 PCP、DCP 和混合 HiSparse

在 16 块 H200 上使用长智能体上下文服务 GLM-5.3 需要两种标准张量并行和数据并行无法提供的机制:预填充上下文并行(PCP),它按 token 将每个提示词拆分到多个 GPU 上;以及解码上下文并行(DCP),它分片 KV 缓存,以便 100 万 token 的上下文能够容纳。结合混合 HiSparse 解码,这个 vLLM 部署(vLLM v0.32.0 或更高版本)在 AgentX 基准测试中,以相同的吞吐量提供了数据并行部署的 1.7-3.2 倍每用户交互性,并且是作者测试过的唯一能够服务 100 万 token 请求的配置。

这是 vLLM 的 GLM-5.3 优化系列的第二部分;第一部分涵盖了在单个 8x H200 节点上的聚合部署中的混合 HiSparse。第二部分涵盖了跨两个 8x H200 节点的预填充/解码分离。

公告内容

vLLM 发布了一篇技术文章,描述了如何在 16 块 H200 上服务 GLM-5.3 长上下文智能体工作负载,这些 H200 被分为一个预填充节点和一个解码节点。文章介绍了三个构建块,并展示了它们如何组合:

  • 预填充上下文并行(PCP) 按 token 而不是按注意力头将每个提示词拆分到多个 GPU 上,这比张量并行更适合 GLM-5.3 的稀疏注意力。
  • 解码上下文并行(DCP) 按 token 分片预填充引擎的 KV 缓存,以便 100 万 token 的上下文能够容纳在预填充节点上。
  • 混合 HiSparse 允许解码引擎将 KV 保留在主机内存中,以便 100 万 token 的请求能够容纳在解码端。

在 SemiAnalysis AgentX 基准测试中,PCP8 与 DCP8 预填充加上混合 HiSparse 解码,在相同吞吐量下提供了数据并行(DP8)部署的 1.7-3.2 倍每用户速度,并将中位首次 token 时间(TTFT)从 1.5-5.2 秒降低到 0.8-0.9 秒。

为什么长智能体上下文会破坏 H200 上的标准并行

智能体工作负载具有长上下文,并且随着每一轮而增长,这对 GPU 内存和预填充吞吐量都造成了压力。在 H200 上,GLM-5.3 的权重消耗了每个 GPU 的大部分内存,留给长上下文 KV 缓存的空间很小。由于每一轮都会向预填充添加更多的工具输出和文件内容,在负载下,预填充引擎可能成为整个部署的瓶颈。仅靠预填充/解码分离并不能解决这个问题。

为什么 DP8 和 TP8 不足

在 8x H200 节点上运行 GLM-5.3 预填充的两种标准方式是数据并行(DP8)和张量并行(TP8),两者都因不同原因而失败:

  • DP8 将每个提示词分配给单个 GPU,因此其注意力无法使用其他七个 GPU。这限制了长提示词的首次 token 时间,并且提示词的 KV 缓存必须适合该单个 GPU 的内存。
  • TP8 将注意力头分区到多个 GPU 上。由于 MLA 的潜在 KV 由所有 64 个头共享,每个 GPU 存储完整的缓存,但只为 8 个头服务。索引器(对每个早期 token 进行评分以选择稀疏 MLA 关注的 2,048 个 token)根本没有分区,因此其二次成本在每个 GPU 上重复。

两种方案都不能在不将整个 KV 缓存保留在每个服务它的 GPU 上的情况下,将一个长提示词的注意力工作分散到八个 GPU 上。PCP 解决了查询端;DCP 解决了 KV 端。

PCP:拆分 token,而不是头

预填充上下文并行按 token 将每个提示词拆分到八个 GPU 上:每个 GPU 使用所有 64 个头计算提示词八分之一的查询。朴素的拆分会不平衡,因为在因果注意力下,一个 token 会关注它之前的所有 token,因此持有提示词末尾的 GPU 将比持有开头的 GPU 做更多的工作。PCP 将提示词切成 16 个块并将它们配对,因此 GPU g 从前端获取块 g,从后端获取块 15 - g,从而给每个 GPU 相同的廉价和昂贵 token 混合。这是论文“Context Parallelism for Scalable Million-Token Inference”(arXiv 2411.01783)中的负载均衡分片。然后,每个 GPU 的新 KV 被全收集,以便每个查询都可以关注完整上下文。

对算术强度的影响是头条数字。在 PCP 下,每个 GPU 只索引自己的 token,因此每个 GPU 只做索引器工作的八分之一,而不是复制所有工作。并且从内存中读取的每个 KV 行现在为所有 64 个头服务,而不是 8 个,将稀疏 MLA 从每字节移动约 26 个 FLOP 提高到约 191 个 FLOP。H200 的 BF16 岭点是每字节 206 个 FLOP,因此 PCP 使稀疏 MLA 接近计算受限。

不复制索引器对于长预填充最重要。索引器的成本随提示词长度二次增长,而稀疏 MLA 的成本仅线性增长,因为每个查询关注固定的 2,048 个 token。从头计算预填充的 FLOP,在 TP8 下,一旦提示词达到约 32K token,索引器就会超过稀疏 MLA;在 PCP8 下,没有 GPU 复制它,交叉点移到约 256K token。

PCP 有两个剩余成本。每个 GPU 必须持有所有注意力权重,而 MoE 专家保持拆分在八个 GPU 上,使用 EP8。并且由于新 KV 每层都被全收集,每个 GPU 最终仍然存储完整的 KV 缓存。这个复制的缓存,而不是计算,限制了上下文长度——而 DCP 消除了它。

DCP:也分片 KV 缓存

解码上下文并行拆分 KV 缓存本身。一个 100 万 token 的 GLM-5.3 请求需要 53.4 GiB 的 FP8 KV,但每个 GPU 只有约 15 GiB 的空间。DCP 将 token 轮询分配到八个 GPU 上,因此每个 GPU 存储每八个 token,同一个请求每个 GPU 只需要 6.7 GiB(53.4 / 8)。

命名是历史性的,不是描述当前部署的。DCP 是为解码构建的,其中每个请求有一个查询 token,KV 缓存是唯一值得拆分的东西;PCP 是为预填充构建的,其中提示词的许多查询 token 是工作。此部署在预填充引擎内运行两者,其中 PCP 拆分查询,DCP 拆分 KV。

由于 DCP 分片缓存,每个 GPU 的查询需要的大部分 KV 现在位于其他 GPU 上。在解码中,DCP 将查询发送到 KV:每个 GPU 关注自己的分片,部分结果与它们的 log-sum-exp 合并。在这个预填充引擎中,方向相反:每层,每个 GPU 将分片全收集到临时的完整上下文副本中,为自己的查询关注,并释放副本。只有持久缓存被分成八份。

两种布局不对齐。一个 GPU 存储每八个 token,但计算块 g 和 15 - g 的查询,这正是每层需要全收集的原因。

全收集的成本

全收集不是免费的:每层它重新发送整个缓存的上下文,因此其成本随上下文长度增长。通过在相同的缓存上下文下,在同一个 PCP8 节点上运行相同的 2K token 预填充块,有和没有 DCP8,隔离效果,DCP8 在高达 64K token 的上下文下每步增加约 6%,在 248K token 时增加到 15%。这是 8 倍 KV 池的代价。作者表示,可以通过将每层的全收集与前一层的计算重叠来减少开销,这是他们目前正在进行的优化。

超过约 250K token,仅 PCP8 无法容纳 KV 缓存,因此 DCP 不再是开销,而是使长提示词成为可能。总之,PCP8 与 DCP8 为预填充引擎提供了速度和空间。

部署:在 16 块 H200 上的预填充/解码分离

该部署是在两个 8x H200 节点上的预填充/解码(P/D)分离设置。两个引擎都使用 FP8 KV 缓存和 MTP 推测解码,带有三个草稿 token(MTP3)。

  • 预填充: 一个 PCP8 x DCP8 x EP8 引擎,具有 512 GiB 的 CPU KV 卸载,以便后续轮次重用其前缀。
  • 解码: 八个 DP 等级,使用 EP8 和来自第一部分的混合 HiSparse(每个等级 48 GiB 主机池加上 16 GiB 卸载),因此解码并发受主机内存而非 HBM 限制。

一个前缀感知的 llm-d 路由器将每个请求发送到预填充引擎,NIXL 连接器将其 KV 缓存移动到解码等级,解码等级将 token 流回。

比较基线使用相同的硬件和相同的总内存:PCP8 x DCP8 预填充与 DP8 预填充(八个 DP 等级,每个等级使用 EP8 和 64 GiB 的 CPU KV 卸载,总共 512 GiB)进行比较,混合 HiSparse 与解码节点上的普通 CPU KV 卸载进行比较,无论哪种方式都有 512 GiB 的主机内存。每个配置都运行相同的 16 个 GPU、主机内存和 vLLM 构建。

AgentX 上的结果

基准测试是 SemiAnalysis AgentX:重放的 Claude Code 轨迹,带有前缀重用,每个并发一个新鲜服务器,运行一小时,MTP3 的合成接受长度固定为 2.99,以便每个配置获得相同的推测加速。吞吐量以每个 GPU 的逻辑 token 每秒(包括缓存 token)衡量——输入加输出 token,计算前缀缓存的输入,在所有 16 个 GPU 上。交互性是 AgentX 的 P90 端到端归一化输出 token 每秒每用户。

测量在两个上下文限制下进行:c8 到 c64 在 142K,c8 到 c32 在 1M。

在 c32 之前,部署主要是预填充受限,因此预填充器产生更大的差异。 在两个设置中都有 HiSparse 解码,PCP8 x DCP8 预填充在相同吞吐量下提供了 DP8 的 1.7-3.2 倍交互性,并将中位 TTFT 从 1.5-5.2 秒降低到 0.8-0.9 秒。解码器在此负载下几乎没有差异:在 c8 和 c16 时,两个 PCP8 x DCP8 配置彼此相差几个百分点,而仅卸载解码在 c8 时略领先。

从 c32 开始,部署变得更加解码受限,HiSparse 解码领先。 在 c64 时,它几乎使吞吐量翻倍,达到每 GPU 每秒 8,340 个逻辑 token,每用户每秒 29.6 个 token,而其他所有配置都下降到每用户每秒 1-2 个 token。

在 1M 上下文时,部署需要两种机制。 一个 DP8 预填充等级无法容纳一个 100 万 token 的请求,仅卸载解码等级也无法容纳。这就是为什么组合配置是唯一测试过的能够服务 100 万 token 上下文的配置。

使功能组合

困难的工程工作是使 PCP、DCP 和混合 HiSparse 等功能组合,因为每个功能都改变了 KV 缓存的布局、调度或移动方式,并且每个组合都必须保持正确和快速。

对于预填充/解码分离,KV 必须在两个引擎之间改变布局。预填充引擎按 token 将每个请求的 KV 分片到八个 GPU 上,而每个解码等级需要完整的 KV——包括 MTP 层的——在其自己的分页布局中。NIXL 连接器在两个节点之间执行此重组,并且从 CPU 卸载的前缀重用必须与其一起工作。

文章中的每个配置都在 Model Runner V2 上运行,这是 vLLM 的新模块化核心,它将模型特定状态排除在公共执行路径之外,并在没有 CPU-GPU 同步的情况下运行推测解码。混合 HiSparse 构建在它之上。

如何复现和所需标志

文章中的所有内容都在 vLLM v0.32.0 或更高版本上运行,使用 vllm/vllm-openai:v0.32.0 镜像。报告的结果是在 vLLM main 分支的提交 9e38b4111a 上测量的,复现 gist 固定提交 2537629eb2。

预填充引擎的关键标志是:

--prefill-context-parallel-size 8 \
--decode-context-parallel-size 8 \
--dcp-comm-backend ag_rs \
--enable-expert-parallel \
--attention-config '{"sparse_mla_force_mqa":true}'

一个标志值得解释。没有 sparse_mla_force_mqa,提示词适合 2,048 token top-k 的预填充批次会走密集 MHA 路径。该标志使它们也保持在稀疏 MLA(MQA)内核上,因此每个 KV 行为所有头服务。

为什么数字有效

三个脚注计算支撑了文章关于内存和计算的主张。稀疏 MLA 读取 2,048 个选定的 KV 行,每行 660 字节(FlashMLA 的 fp8_ds_mla 格式中的 656 字节 FP8 KV 加上 4 字节索引),每个查询约 1.35 MB。每个头为 BF16 查询和输出添加 2,176 字节,并每行执行 2,176 个 FLOP(QK 在 576 维上,PV 在 512 维上)。因此,8 个头在 1.37 MB 上执行 35.7 MFLOP,约每字节 26 个 FLOP,而 64 个头在 1.49 MB 上执行 285 MFLOP,约每字节 191 个 FLOP。

对于 H200 SXM,BF16 岭点是 989 密集 BF16 TFLOP/s 除以 4.8 TB/s 带宽,即每字节 206 个 FLOP。数据表中的 1,979 TFLOP/s 数字假设 2:4 稀疏性。

53.4 GiB 的数字来自每 token KV 核算:78 层 x 656 字节的 MLA KV,21 个索引器层 x 132 字节的索引器键(128 个 FP8 值加上 4 字节缩放),以及 MTP 层的 788 字节,总共 54,728 字节。对于 N = 1,048,576 个 token,即 54,728 MiB,约 53.4 GiB。

谁完成了这项工作

这项工作由 Red Hat 的 Roberto L. Castro、Simon Veitner、Matthew Bonanni 和 Lucas Wilkinson 以及 Mistral 的 Nicolo Lucchesi 完成。Red Hat 的 Maroon Ayoub 和 Robert Shaw 因压力测试部署、报告错误和修复错误而受到感谢。

Sources