@[TOC]双 DGX Spark 部署 DeepSeek V4 Flash 实战

两台 NVIDIA DGX Spark (GB10),200G RoCE 直连,Docker 部署 DeepSeek V4 Flash 200B MoE 大模型,推理速度 38 tok/s,支持 200K 上下文。


1. 硬件环境

项目 DGX-1 (Head) DGX-2 (Worker)
型号 DGX Spark DGX Spark
CPU Grace ARM 20核 Grace ARM 20核
GPU GB10 (Blackwell) GB10 (Blackwell)
统一内存 128GB LPDDR5X 128GB LPDDR5X
存储 1TB NVMe 1TB NVMe
互联 ConnectX-7 200G RoCE ConnectX-7 200G RoCE
管理 IP 192.168.0.21 192.168.0.22
高速 IP 192.168.10.58 192.168.10.59

2. 软件栈

组件 版本/说明
操作系统 Ubuntu 24.04 LTS (aarch64)
Docker 原生安装 + nvidia-container-toolkit
vLLM v0.21.1rc1 + SM12x 补丁 (jasl 分支)
自定义镜像 vllm-node-dsv4:latest (22.7GB, 自构建)
CUDA 12.x (Blackwell SM12.1a)
NCCL IB/RoCE 传输层
Swap 64GB (防止 OOM)

为什么用补丁版 vLLM 而不是 pip 安装?

官方 vLLM 0.22.0 有两个致命问题:① mp backend 不支持跨节点 TP(报 local_world_size > visible devices);② Gloo 进程组在 DGX SPARK 上崩溃(Gloo connectFullMesh failed)。打了 SM12x 补丁后,mp backend 真正支持跨节点张量并行。

3. 架构

┌─────────────────────────┐      ┌─────────────────────────┐
│  DGX-1 (Head, rank=0)   │      │ DGX-2 (Worker, rank=1)  │
│                         │      │                         │
│  ┌───────────────────┐  │      │  ┌───────────────────┐  │
│  │  vllm-ds4 容器     │  │      │  │  vllm-ds4 容器     │  │
│  │  TP=0, EP=0       │◄─┼──────┼─►│  TP=1, EP=1       │  │
│  │  HTTP API :8000   │  │ RoCE │  │  (headless)       │  │
│  └───────────────────┘  │200G  │  └───────────────────┘  │
│                         │      │                         │
│  GB10 128GB 统一内存     │      │  GB10 128GB 统一内存     │
└─────────────────────────┘      └─────────────────────────┘
         ▲
         │ HTTP (OpenAI 兼容 API)
         ▼
    ┌─────────┐
    │ 客户端   │
    └─────────┘

关键设计决策:

  • B12X Mxfp4 MoE 内核替代标准 expert-parallel:更快(~38 tok/s),但与 EP 互斥
  • MTP 投机解码 x2:模型内置 Multi-Token Prediction 头,无损加速 50%+
  • mp backend 替代 Ray:无需启动 Ray 集群,简化运维
  • FP8 KV Cache:block-size 256,prefix caching 启用

4. 部署步骤

4.1 前置准备

# 两台节点都要做
sudo fallocate -l 64G /swapfile
sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# 配置 Docker 镜像加速(中国网络环境)
sudo tee /etc/docker/daemon.json << 'EOF'
{"registry-mirrors": ["https://docker.nju.edu.cn"]}
EOF
sudo systemctl restart docker

# 确认 IB 设备
rdma link show  # 找到 ACTIVE 的 HCA,通常是 rocep1s0f1

4.2 启动 Worker(必须先启动)

# DGX-2 (192.168.0.22)
docker run -d \
  --name vllm-ds4 --gpus all --net=host --ipc=host \
  --shm-size=64g --ulimit memlock=-1 --ulimit stack=67108864 \
  --device /dev/infiniband:/dev/infiniband \
  -v /home/wangdefa/models:/models \
  -e NODE_RANK=1 -e HEADLESS=1 -e MASTER_ADDR=192.168.10.58 \
  -e NCCL_NET=IB -e NCCL_IB_DISABLE=0 -e NCCL_IB_HCA=rocep1s0f1 \
  -e NCCL_SOCKET_IFNAME=enp1s0f1np1 -e NCCL_IB_GID_INDEX=0 \
  -e NCCL_CROSS_NIC=0 -e NCCL_CUMEM_ENABLE=0 -e NCCL_IGNORE_CPU_AFFINITY=1 \
  -e NCCL_DEBUG=WARN -e VLLM_ALLOW_LONG_MAX_MODEL_LEN=1 \
  -e VLLM_SPARSE_INDEXER_MAX_LOGITS_MB=256 -e VLLM_USE_B12X_MOE=1 \
  --entrypoint /usr/local/bin/dsv4-vllm-entrypoint \
  vllm-node-dsv4:latest \
  serve /models/DeepSeek-V4-Flash \
    --distributed-executor-backend mp --nnodes 2 --node-rank 1 \
    --master-addr 192.168.10.58 --master-port 25000 \
    --tensor-parallel-size 2 \
    --kv-cache-dtype fp8 --block-size 256 \
    --max-model-len 200000 --gpu-memory-utilization 0.75 \
    --max-num-seqs 6 --max-num-batched-tokens 4096 \
    --enable-prefix-caching --enable-flashinfer-autotune \
    --tokenizer-mode deepseek_v4 --reasoning-parser deepseek_v4 \
    --reasoning-config '{"reasoning_parser":"deepseek_v4","reasoning_start_str":"","reasoning_end_str":""}' \
    --speculative-config '{"method":"mtp","num_speculative_tokens":2}' \
    --api-key sk-xxxx --headless --trust-remote-code

4.3 等 5 秒后启动 Head

# DGX-1 (192.168.0.21)
docker run -d \
  --name vllm-ds4 --gpus all --net=host --ipc=host \
  --shm-size=64g --ulimit memlock=-1 --ulimit stack=67108864 \
  --device /dev/infiniband:/dev/infiniband \
  -v /home/wangdefa/models:/models \
  -e NODE_RANK=0 -e MASTER_ADDR=192.168.10.58 \
  -e NCCL_NET=IB -e NCCL_IB_DISABLE=0 -e NCCL_IB_HCA=rocep1s0f1 \
  -e NCCL_SOCKET_IFNAME=enp1s0f1np1 -e NCCL_IB_GID_INDEX=0 \
  -e NCCL_CROSS_NIC=0 -e NCCL_CUMEM_ENABLE=0 -e NCCL_IGNORE_CPU_AFFINITY=1 \
  -e NCCL_DEBUG=WARN -e VLLM_ALLOW_LONG_MAX_MODEL_LEN=1 \
  -e VLLM_SPARSE_INDEXER_MAX_LOGITS_MB=256 -e VLLM_USE_B12X_MOE=1 \
  --entrypoint /usr/local/bin/dsv4-vllm-entrypoint \
  vllm-node-dsv4:latest \
  serve /models/DeepSeek-V4-Flash \
    --distributed-executor-backend mp --nnodes 2 --node-rank 0 \
    --master-addr 192.168.10.58 --master-port 25000 \
    --tensor-parallel-size 2 \
    --kv-cache-dtype fp8 --block-size 256 \
    --max-model-len 200000 --gpu-memory-utilization 0.75 \
    --max-num-seqs 6 --max-num-batched-tokens 4096 \
    --enable-prefix-caching --enable-flashinfer-autotune \
    --tokenizer-mode deepseek_v4 --reasoning-parser deepseek_v4 \
    --reasoning-config '{"reasoning_parser":"deepseek_v4","reasoning_start_str":"","reasoning_end_str":""}' \
    --speculative-config '{"method":"mtp","num_speculative_tokens":2}' \
    --api-key sk-xxxx --trust-remote-code

4.4 等待就绪

首次启动约 8 分钟,阶段分布:

时间 阶段
0-15s NCCL 初始化,rank 分配
15s-3min 模型权重加载(46 个 safetensors 分片)
3-5min DeepGEMM E8M0 启用,B12X MoE 内核选择
5-7min TileLang JIT 编译
7-8min FlashInfer autotune + CUDA graph 捕获
8min Application startup complete
# 监控日志
docker logs -f vllm-ds4

# 确认就绪
curl http://192.168.0.21:8000/health

5. 性能数据

指标 数值
模型参数 ~200B (MoE, 43层, 4096 hidden size)
模型磁盘占用 ~155GB (46 分片, 内置 FP8 量化)
KV Cache FP8, ~9 GiB 可用 (200K 上下文)
Decode 速度 ~38 tok/s (B12X + MTP x2)
无 MTP 速度 ~26 tok/s
加速比 ~50%
上下文窗口 200,000 tokens
最大并发 6 sequences
内存占用 ~96 GiB / 128 GiB (每节点)

6. API 接入

端点: http://192.168.0.21:8000/v1/chat/completions
模型: DeepSeek-V4-Flash
认证: Bearer <api-key>

curl 示例

curl http://192.168.0.21:8000/v1/chat/completions \
  -H "Authorization: Bearer sk-xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "DeepSeek-V4-Flash",
    "messages": [{"role": "user", "content": "你好"}],
    "max_tokens": 1024
  }'

Python 示例

from openai import OpenAI

client = OpenAI(
    base_url="http://192.168.0.21:8000/v1",
    api_key="sk-xxxx"
)
response = client.chat.completions.create(
    model="DeepSeek-V4-Flash",
    messages=[{"role": "user", "content": "你好"}]
)

7. 踩坑记录

坑 1:B12X MoE 与 expert-parallel 互斥

B12X Mxfp4 MoE 内核不接受 ep_size=2 的配置,报错 Mxfp4 MoE backend 'B12X' does not support FusedMoEParallelConfig(tp_size=1, ep_size=2)。选择:开 B12X(更快) 开 EP(省内存),不能同时开。

坑 2:TileLang JIT 编译需大栈空间

DeepSeek V4 的 mHC (multi-head cache) 内核由 TileLang JIT 编译生成。Docker 默认栈空间不够,不设 --ulimit stack=67108864 会导致内核编译静默崩溃。

坑 3:GB10 统一内存的 NCCL 兼容性

GB10 的 CPU+GPU 共享 128GB LPDDR5X,NCCL 的 CUDA managed memory 优化在此架构上不兼容。必须设置:

  • NCCL_CUMEM_ENABLE=0:回退到显式内存拷贝
  • NCCL_IGNORE_CPU_AFFINITY=1:禁用容器 CPU pinning
  • NCCL_CROSS_NIC=0:单 NIC 拓扑

坑 4:Worker 必须先启动

mp backend 的 init_process_group 等待所有 rank 就绪。如果 Head 先启动而 Worker 未加入,Head 会在 NCCL 超时后(~10 min)崩溃。正确顺序:先 Worker,等 5 秒,再 Head

坑 5:vLLM 0.21.1rc1 的 master-addr 语法

v0.21.1rc1 使用 --master-addr / --master-port 作为 CLI 参数,而 v0.22.0 使用 MASTER_ADDR / MASTER_PORT 环境变量。用错语法会导致 master_addr 静默回退到 127.0.0.1,跨节点 NCCL 握手失败但无报错。

坑 6:RoCE IB GID Index

直连(无交换机)场景必须用 NCCL_IB_GID_INDEX=0(link-local GID)。用 index 3 会导致两端 GID 类型不一致,报 ibv_modify_qp failed with Invalid argument

坑 7:Docker Hub 不可达

DGX Spark 在中国网络环境下 Docker Hub 超时。需配置国内镜像加速(如 docker.nju.edu.cn),且镜像必须在白名单内。

坑 8:64GB swap 是硬性要求

DGX Spark 仅 128GB 统一内存,加载 200B 模型时 page cache + 模型权重 + CUDA 编译中间结果轻松超过 121GB。16GB swap 不够(实测 OOM),32GB 理论边界,200B 模型安全值 64GB

8. 监控与维护

# 查看容器状态
ssh wangdefa@192.168.0.21 'docker ps --filter name=vllm-ds4'

# 查看实时日志
ssh wangdefa@192.168.0.21 'docker logs -f vllm-ds4 --tail 50'

# 重启服务
ssh wangdefa@192.168.0.21 'docker restart vllm-ds4'

# 一键重新部署
cd ~/.hermes/profiles/guijiqichengse/scripts && python3 deploy_dsv4.py

部署日期:2026-06-21 验证通过
硬件:NVIDIA DGX Spark x2
环境:Ubuntu 24.04 LTS, Docker, vLLM v0.21.1rc1 + SM12x patch

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐