概述#

本文记录在两台 DGX Spark 上首次以 vLLM TP=2(跨节点张量并行)方式部署 Qwen3.5-35B-A3B 的完整过程。这次实验先得到几条比较初步的观察:

  • TP=2 跨节点推理可以跑通,短请求成功完成
  • 成功样本吞吐约 21–31 tok/s,与单机 TP=1(~29 tok/s)基本持平
  • 稳定性不足:代码生成 case 在约 300 秒后返回 HTTP 500
  • 按这轮实验结果看,如果是追求更稳妥的生产方案,我目前更倾向于两台节点各自独立运行 TP=1,再通过 LiteLLM / Nginx 做负载均衡

技术背景#

DGX Spark 与统一内存#

DGX Spark 搭载 NVIDIA GB10 Grace Blackwell Superchip,其关键特征是 128GB LPDDR5X 统一内存(CPU+GPU 共享),带宽 273 GB/s。

与独立显存的传统 GPU 不同,统一内存没有独立的 VRAM 分区。这意味着:

  • --gpu-memory-utilization 不能像常规设置那样给到 0.9,需要保守设为 0.7,为内存碎片留出余量
  • 按我这轮实验里的环境约束,最好关闭 swap,否则系统在内存压力下很容易出现明显卡顿甚至失去响应
  • 模型权重、KV cache、推理中间态都在同一块 128GB 池子里分配

vLLM 与 Tensor Parallel#

vLLM 是一个高性能 LLM 推理引擎,提供 OpenAI 兼容 API、PagedAttention 显存管理、持续批处理等特性。它原生支持 Tensor Parallel(张量并行):将模型的计算图按张量维度切分到多个 GPU 上执行,各 GPU 之间通过 NCCL(NVIDIA GPU 间通信库)进行 all-reduce 通信同步中间结果。

  • TP=1:单 GPU 承载完整模型(单机默认)
  • TP=2:模型张量切分到 2 个 GPU 上,每个 GPU 只持有模型的一半参数
  • TP 粒度越细,单卡内存压力越低,但跨卡通信开销越大

通常情况下,TP 用于同一台机器内的多卡并行。这次实验的关键不同在于:两台物理独立的 DGX Spark 各出 1 张 GPU,组成一个 TP=2 推理实例。

跨节点 TP 的挑战#

跨节点 Tensor Parallel 并非 vLLM 的主要设计场景。主要风险包括:

  1. NCCL 通信延迟:节点间通过以太网(非 InfiniBand),all-reduce 操作延迟显著高于机内 NVLink/PCIe
  2. Hang 风险:社区已知跨节点 TP 在特定情况下可能出现进程挂死
  3. 稳定性不确定:短请求可能正常返回,但长文本生成或高并发场景可能触发超时或 OOM(Out of Memory)

这也是本次实践要验证的核心问题。

实验环境#

硬件与网络#

项目
节点 2 台 DGX Spark (GB10)
Coordinator (rank 0) 100.97.87.120
Worker (rank 1) 100.67.164.92
GPU 驱动 580.126.09
CUDA 13.0
Docker 镜像 vllm/vllm-openai:gemma4-cu130 (v0.18.2)
NCCL 网卡 enp1s0f0np0(以太网,无 InfiniBand)

模型#

Qwen3.5-35B-A3B-Claude-4.6-Opus-Reasoning-Distilled

  • MoE(Mixture of Experts,混合专家)架构,总参数 35B,每 token 激活约 3B
  • FP8(8-bit 浮点)量化
  • 多模态模型(本次仅使用文本能力)

选择它的原因:

  1. 模型足够大,单机虽能装载但已接近内存边界,适合验证跨节点分摊
  2. MoE 架构每 token 激活参数少,理论上比 dense 大模型更适合分布式推理
  3. 这是当前 repo 里已成功跑通 TP=2 的实际对象

vLLM 配置#

参数
--tensor-parallel-size 2
--pipeline-parallel-size 1
--nnodes 2
--distributed-executor-backend mp(multiprocessing)
--gpu-memory-utilization 0.7
--kv-cache-dtype fp8
--max-model-len 8192
--max-num-seqs 64
VLLM_ATTENTION_BACKEND FLASHINFER
VLLM_USE_FLASHINFER_MOE_FP8 1
NCCL_IB_DISABLE 1

部署架构#

  • Coordinator(rank 0):对外暴露 OpenAI 兼容 API(port 8000)
  • Worker(rank 1):headless(无对外 API)方式作为分布式参与者加入

两台机器共同组成一个 TP=2 实例,而非各自独立运行服务。

部署过程#

通过 Ansible 编排两台节点同时启动,分为四步:

  1. 预检查:确认 Docker 可用、GPU 可见、NCCL 网卡存在、模型缓存已就位
  2. 解析模型路径:找到 HuggingFace 缓存中的模型目录并映射到容器挂载路径
  3. 启动 vLLM:两台节点各自执行 run-vllm-tp2.sh,通过 TP2_NODE_RANK 区分 coordinator/worker
  4. 验证:确认 coordinator API 端口可达,TP=2 分布式启动无报错

核心启动命令(两节点分别以 rank 0/1 执行):

CUDA_VISIBLE_DEVICES=0 \
VLLM_ATTENTION_BACKEND=FLASHINFER \
VLLM_USE_FLASHINFER_MOE_FP8=1 \
vllm serve <model-path> \
  --distributed-executor-backend mp \
  --nnodes 2 \
  --node-rank <0|1> \
  --tensor-parallel-size 2 \
  --pipeline-parallel-size 1 \
  --master-addr <coordinator-ip> \
  --master-port 29500 \
  --gpu-memory-utilization 0.7 \
  --kv-cache-dtype fp8 \
  --max-model-len 8192 \
  --max-num-seqs 64

Benchmark#

方法#

目标不是做大盘压测,而是验证 TP=2 路径在真实请求下的基本可用性。

  • 通过 coordinator 的 /v1/completions 接口发请求
  • temperature=0, stream=false
  • 3 个 case:short-greeting(短文本)、memory-summary(摘要生成)、code-snippet(代码生成)
  • 记录 HTTP 状态码、completion tokens、总延迟、tokens/s
  • benchmark 前后各采集一次节点内存/GPU 快照

结果#

Case HTTP Completion Tokens Latency Tokens/s 说明
short-greeting 200 32 1534 ms 20.86 成功
memory-summary 200 96 3088 ms 31.09 成功
code-snippet 500 0 300791 ms 0.0 约 300 秒后返回 EngineCore 错误

成功完成的两个 case 吞吐落在 20.86–31.09 tok/s 区间。

内存快照#

节点 基准 benchmark 后 GPU 利用率变化
Coordinator 98 Gi 97 Gi 0% → 96%
Worker 90 Gi 90 Gi 0% → 0%

两台节点统一内存占用均处于高位,符合预期(模型已加载)。但 worker 节点 GPU 利用率在 benchmark 后仍为 0%,提示可能存在 NCCL 通信不均衡或负载分配问题。

关键观察#

  1. TP=2 跨节点推理在这轮测试里可以跑通:短文本请求成功返回,说明双节点 TP 的分布式推理闭环至少已经建立
  2. 稳定性不足code-snippet case 在约 300 秒后返回 HTTP 500(EngineCore 错误),说明更长、更复杂的生成场景仍有问题
  3. Worker GPU 利用率为 0%:这与 NCCL 跨以太网 all-reduce 的延迟和通信瓶颈相符,是跨节点 TP 的典型表现

与单机结果对照#

作为参考,同一模型在单台 DGX Spark(TP=1)上的 benchmark 结果为:

场景 Tokens 延迟 Tokens/s
短回答 50 14.22s 3.5(冷启动)
中等解释 150 5.20s 28.9
代码生成 200 6.83s 29.3
长解释 400 13.34s 30.0

单机稳定吞吐约 29 tok/s,TP=2 成功样本的吞吐范围(21–31 tok/s)与之接近甚至略高,但 TP=2 的致命弱点是 稳定性(出现了 500 错误),而单机没有出现此类问题。

结论#

  • 两台 DGX Spark 以 vLLM TP=2 方式部署 Qwen3.5-35B-A3B 可以跑通,短请求已成功完成
  • 成功样本吞吐约 21–31 tok/s,与单机 TP=1 结果(~29 tok/s)基本持平
  • 但跨节点 TP=2 稳定性尚未得到验证:代码生成 case 在约 300 秒后返回 HTTP 500,worker GPU 利用率异常
  • 对于生产场景,按目前这组结果,我更倾向的做法是:两台节点各自独立运行 TP=1 实例,通过 LiteLLM 或 Nginx 做负载均衡,而不是直接上跨节点 TP

本次实验是一份实践记录而非结论性报告,重点在于沉淀跨节点 TP=2 的部署流程与基线数据,为后续进一步优化或排查提供参考。

后续实验方向#

结合 2026 年社区已有的实验结果(NVIDIA Developer Forums、GitHub 社区 Docker 项目等),以下是从本次 TP=2 实践出发可以继续验证的方向:

1. 切换 Ray 后端替代 MP 后端#

本次实验使用的是 --distributed-executor-backend mp(multiprocessing)。按我目前查到的社区案例,Ray 后端--distributed-executor-backend ray)在多节点编排上看起来更成熟,也是一些社区 Docker 镜像(eugr/spark-vllm-dockerbjk110/spark_vllm_docker)的默认选择。

后续可对比 MP vs Ray 在以下维度的差异:

  • 长文本生成的稳定性(是否仍出现 HTTP 500)
  • Worker GPU 利用率是否恢复正常
  • NCCL 通信延迟与吞吐量

2. 排查 PyTorch 版本与 CUDA Graph 兼容性#

社区已确认一个典型的 TP=2 挂死根因:PyTorch 版本不匹配(编译用 2.10.0 vs 要求的 2.9.1)会导致 CUDA Graph(GPU 执行图优化技术)异常,进而引发一个节点掉线、另一个节点 GPU 100% 空转。

可验证的措施:

  • 确认当前 vLLM 镜像内的 PyTorch 版本
  • 尝试 --enforce-eager 跳过 CUDA Graph,观察是否改善稳定性
  • 如有条件,切换到社区验证过的 Docker 镜像

3. NCCL 网络层优化#

本次实验 NCCL 走的是普通以太网(enp1s0f0np0),NCCL_IB_DISABLE=1。DGX Spark 实际配备 ConnectX-7 网卡,支持 200Gbps RoCE(RDMA over Converged Ethernet,在以太网上实现远程直接内存访问)。

后续可验证:

  • 启用 RDMA/RoCE 模式(NCCL_IB_DISABLE=0,配置 NCCL_IB_HCA 包含两个 NIC 半区)
  • 通过 NCCL_DEBUG=INFO 确认 vLLM 启动时使用的是 Using network IB 而非 TCP
  • all_gather_perf 独立验证 RoCE 带宽是否饱和(社区实测约 24.38 GB/s / ~195 Gbps @ MTU 9000)
  • 对比 TCP vs RoCE 模式下 TP=2 的吞吐与稳定性差异

4. 量化方案对比:AWQ vs NVFP4 vs FP8#

按我目前看到的社区实验,NVFP4 在 DGX Spark 上暂时没体现出明显优势,甚至可能需要模型补丁;而 AWQ(Activation-aware Weight Quantization,激活感知权重量化,压缩到 4-bit INT4)在当前成熟度看起来更高,性能和推理质量也更稳定一些。

可对比测试:

量化方案 预期 tok/s 稳定性 备注
FP8(当前) ~29 基准 本次实验使用
AWQ 4bit 待测 社区中更常见 MiniMax-M2.1-AWQGLM-4.7-AWQ 已在社区验证
NVFP4 待测 需补丁 单节点 decode 可达 61-65 tok/s(Nemotron-30B),但 TP=2 兼容性待确认

5. 更大模型的 TP=2 验证#

社区确认两台 DGX Spark 可以承载 130B 参数级模型(含 KV cache 和 speculative decoding)。结合 TP=2 的内存分摊优势,可尝试:

  • Qwen3.5-122B-FP8(社区 Docker 已有 preset,TP=2)
  • Qwen3.5-397B-INT4(INT4 量化后 TP=2 可跑)

这可能会是 TP=2 更有说服力的使用场景:单机较难装载的模型,通过跨节点张量切分实现推理。

6. 四节点集群#

NVIDIA 已在 2026 年 3 月官方支持 四节点 DGX Spark 组网(512GB 共享内存)。如果有条件扩展到 4 台,可以验证:

  • TP=4 下的模型承载能力(397B 甚至更大)
  • 是否需要 RoCE 200GbE 交换机
  • 三节点环形拓扑 vs 四节点全互联的通信差异

7. 内存调优#

统一内存是 DGX Spark 的核心特征也是瓶颈。可进一步验证:

  • --gpu-memory-utilization 从 0.7 逐步调高到 0.88(社区里较常见的取值),观察吞吐与 OOM 风险
  • vm.swappiness=10 的系统级调优效果
  • KV cache 大小与最大上下文长度的权衡(更长的 context 需要更低的 GPU memory utilization)

优先级建议#

如果只能选一两个方向继续,按当前信息我会优先看:

  1. 切换 Ray 后端 + 排查 PyTorch 版本 — 最可能直接解决本次出现的 HTTP 500 稳定性问题
  2. 启用 RoCE + 验证 NCCL IB 模式 — 跨节点 TP 的网络层是最大瓶颈,RoCE 相比 TCP 的延迟差异可能决定 TP=2 是否可用

其他实验记录#

本文仅聚焦 TP=2 跨节点部署这一条主线。完整的实验过程中还包含大量单机测试、模型筛选、失败尝试,本文不再赘述。所有实验的原始数据、脚本和报告均开源在 GitHub:

👉 meirongdev/nv-dgx-spark

单机 Benchmark#

模型 架构 后端 tok/s 状态 报告
Gemma-4-31B-IT-NVFP4 Dense (31B 全激活) TRITON_ATTN 7.3 ✅ 完成 benchmark report
Qwen3.5-35B-A3B-Claude-Distilled MoE (35B/3B 活跃) FLASHINFER MoE FP8 29.3 ✅ 完成 MoE 对比报告

Gemma-4 的 7.3 tok/s 远低于社区预期(25-40 tok/s),我当时的判断是其异构 head size(256/512)导致 FlashInfer 不可用(ValueError: head_size not supported),回退到 Triton 后性能下降 3-5x。按这次排查结果看,这更像是架构层面的限制,至少不是单靠几项常规配置就能直接修好的问题。

失败的模型测试#

模型 失败原因 详情
MiniMax-M2.5-NVFP4 (~100B MoE) OOM,内存占用 126GB 超过 128GB 统一内存安全上限
Qwen3-235B-A22B-NVFP4 (235B/22B MoE) OOM,内存占用 125GB 需 112GB+ GPU 内存,超出统一内存安全阈值
Qwen3.5-397B-A17B (397B/17B MoE) 模型体积 >128GB 明确不适合单机部署

详见 MoE 模型对比报告

其他问题记录#

  • 缓存模型缺配置文件:本地缓存的 Qwen3.5-35B-A3B-Claude-Distilled 缺少 preprocessor_config.json,需从 HuggingFace 官方 Qwen/Qwen3.5-35B-A3B 补全后才能运行
  • TP=2 Worker GPU 利用率 0%:benchmark 前后快照均显示 worker 节点 GPU 利用率为 0%,提示 NCCL 通信或负载分配可能存在异常

基础设施代码#

Repo 中除实验报告外,还包含完整的部署与管理工具:

类型 文件 用途
部署脚本 scripts/run-vllm-tp2.sh TP=2 单节点容器启动
部署脚本 scripts/vllm-benchmark.sh 单机多模型自动化 benchmark
部署脚本 scripts/vllm-tp2-benchmark.sh TP=2 benchmark 采集与报告生成
部署脚本 scripts/monitor-unified-memory.sh 统一内存实时监控(含 OOM 预警)
Ansible Playbook playbooks/vllm-deploy.yml 单机 vLLM 部署 + 系统加固
Ansible Playbook playbooks/vllm-tp2-deploy.yml TP=2 双节点部署
Ansible Playbook playbooks/vllm-tp2-validate.yml TP=2 验证(健康检查 + 冒烟测试)
Ansible Playbook playbooks/vllm-tp2-stop.yml TP=2 停止
配置 config/vllm.env vLLM 环境变量(FlashInfer、NCCL、内存限制等)
配置 config/vllm.service systemd service 模板(含 OOM 保护)
入口 Makefile 所有操作的统一入口

设计文档#

Repo 的 docs/superpowers/ 目录下还保留了 TP=2 benchmark 功能的完整设计文档与实施计划:


附录:术语速查#

术语 解释
DGX Spark NVIDIA 的个人 AI 工作站,搭载 GB10 Superchip,128GB 统一内存,面向推理场景
GB10 / Grace Blackwell Superchip NVIDIA SoC,集成 20 核 ARM CPU + Blackwell GPU,共享 128GB LPDDR5X 内存,带宽 273 GB/s
统一内存 (Unified Memory) CPU 和 GPU 共享同一块内存池,无独立显存。模型权重、KV cache、中间态都在这块池子里分配
MoE (Mixture of Experts) 混合专家模型。模型包含多个"专家"子网络,推理时只激活部分专家,因此总参数大但实际计算量小
KV Cache Key-Value Cache,推理过程中缓存的注意力中间状态。避免每个 token 生成时重复计算前文,但占用大量显存
NCCL NVIDIA Collective Communications Library,GPU 间通信库。TP 场景下 GPU 通过 NCCL 同步数据
all-reduce 分布式通信操作:多个 GPU 各自有数据,求和/平均后广播回所有 GPU
FlashInfer NVIDIA 的推理加速内核库,针对 Blackwell 等新一代 GPU 架构优化,vLLM 的 attention 和 MoE 计算后端
InfiniBand 高性能网络互连技术,数据中心 GPU 间通信常用,延迟远低于以太网。DGX Spark 未配备
RoCE RDMA over Converged Ethernet,在以太网上实现远程直接内存访问,绕过 CPU 直接读写远端内存
ConnectX-7 NVIDIA 的 SmartNIC 网卡芯片,DGX Spark 内置,支持 200Gbps RoCE
CUDA Graph NVIDIA 的 GPU 执行图优化技术,预录制 kernel 序列减少 CPU 启动开销。某些 PyTorch 版本下会引发兼容性 hang
AWQ 激活感知的权重量化方法,压缩到 4-bit INT4,体积缩小约 4 倍
NVFP4 NVIDIA 的 4-bit 浮点量化格式,专为 Blackwell 设计,理论性能优于 AWQ,但当前成熟度不如 AWQ