欢迎光临
我们一直在努力

DGX Spark GB10 双机实战:从 Qwen3.8 -27B 单机优化到 DeepSeek-V4-Flash 双机 TP=2 部署与性能调优全记录

关键词 / 建议标签:DGX Spark、GB10、大模型部署、vLLM、SGLang、DeepSeek-V4-Flash、Qwen3.8-27B、NVFP4、TP=2、RoCE、推理性能优化

说明:文中主机名、内网地址、用户名均已做脱敏处理(示例值),命令与参数保持可直接参考的完整性。


1. 引言:为什么用两台 DGX Spark 跑本地大模型

DGX Spark(GB10)是单机 128GB 统一内存的桌面级 AI 算力盒子:单机可以跑 30B 级模型,但要上 200B+ 参数的 MoE(如 DeepSeek-V4-Flash),单机内存不够,必须双机甚至多机。

本文完整记录了我们在一对 DGX Spark 上的两段真实工程实践:

  • 单机生产线:Qwen3.8-27B(NVFP4 + DFLASH2 投机解码)的 SGLang 部署与性能优化(短提示 56 tok/s,256K 上下文);
  • 双机攻坚线:先用 SGLang 完成 Qwen3.8-27B 双机 TP=2 全链路验证(code 高并发聚合 +35–45%),随后将 284B 的 DeepSeek-V4-Flash-0731 以 vLLM TP=2 + DSpark 投机解码跑起来(短提示 73 tok/s,1M 上下文长文检索通过)。
  • 此外还有三个"反直觉"的实测结论:双机不是 2 倍速、换 NVFP4 权重没有免费午餐、GPU 利用率 95% 却只烧 42W —— 这正是 GB10 的带宽天花板。如果你正准备折腾双机,本文的坑单和性能数据可以帮你省掉大量试错。


    2. 硬件与网络基线

    2.1 设备规格

    项目规格
    SoC GB10(aarch64,Blackwell 架构 SM121)
    内存 128 GB LPDDR5x 统一内存(UMA),带宽约 273 GB/s
    GPU 每台 1 张 → TP>1 必须跨节点(单机只能 TP=1)
    互联 ConnectX-7,QSFP 口仅以太网模式,每口 200 Gb/s(每物理口 = 2 个逻辑口)
    两机连接 CX7 直连 RoCE(无交换机)

    2.2 高速链路配置要点

    项目说明
    数据面网卡 enp1s0f1np1(两端同名,Head 192.168.101.10 / Worker 192.168.101.11,示例值)
    MTU 两端必须一致;社区实测配置 9000(本机基线 4200,运行时临时改可生效)
    RoCE 设备 rocep1s0f1(两端)
    RoCEv2 GID 索引 必须按节点自动探测(本机实测 Head=3 / Worker=4,且会随重启漂移)

    整机拓扑:

    #mermaid-svg-w4dpKtjr3mIz67G9{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-w4dpKtjr3mIz67G9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-w4dpKtjr3mIz67G9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-w4dpKtjr3mIz67G9 .error-icon{fill:#552222;}#mermaid-svg-w4dpKtjr3mIz67G9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-w4dpKtjr3mIz67G9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-w4dpKtjr3mIz67G9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-w4dpKtjr3mIz67G9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-w4dpKtjr3mIz67G9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-w4dpKtjr3mIz67G9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-w4dpKtjr3mIz67G9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-w4dpKtjr3mIz67G9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-w4dpKtjr3mIz67G9 .marker.cross{stroke:#333333;}#mermaid-svg-w4dpKtjr3mIz67G9 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-w4dpKtjr3mIz67G9 p{margin:0;}#mermaid-svg-w4dpKtjr3mIz67G9 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-w4dpKtjr3mIz67G9 .cluster-label text{fill:#333;}#mermaid-svg-w4dpKtjr3mIz67G9 .cluster-label span{color:#333;}#mermaid-svg-w4dpKtjr3mIz67G9 .cluster-label span p{background-color:transparent;}#mermaid-svg-w4dpKtjr3mIz67G9 .label text,#mermaid-svg-w4dpKtjr3mIz67G9 span{fill:#333;color:#333;}#mermaid-svg-w4dpKtjr3mIz67G9 .node rect,#mermaid-svg-w4dpKtjr3mIz67G9 .node circle,#mermaid-svg-w4dpKtjr3mIz67G9 .node ellipse,#mermaid-svg-w4dpKtjr3mIz67G9 .node polygon,#mermaid-svg-w4dpKtjr3mIz67G9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-w4dpKtjr3mIz67G9 .rough-node .label text,#mermaid-svg-w4dpKtjr3mIz67G9 .node .label text,#mermaid-svg-w4dpKtjr3mIz67G9 .image-shape .label,#mermaid-svg-w4dpKtjr3mIz67G9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-w4dpKtjr3mIz67G9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-w4dpKtjr3mIz67G9 .rough-node .label,#mermaid-svg-w4dpKtjr3mIz67G9 .node .label,#mermaid-svg-w4dpKtjr3mIz67G9 .image-shape .label,#mermaid-svg-w4dpKtjr3mIz67G9 .icon-shape .label{text-align:center;}#mermaid-svg-w4dpKtjr3mIz67G9 .node.clickable{cursor:pointer;}#mermaid-svg-w4dpKtjr3mIz67G9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-w4dpKtjr3mIz67G9 .arrowheadPath{fill:#333333;}#mermaid-svg-w4dpKtjr3mIz67G9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-w4dpKtjr3mIz67G9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-w4dpKtjr3mIz67G9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w4dpKtjr3mIz67G9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-w4dpKtjr3mIz67G9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w4dpKtjr3mIz67G9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-w4dpKtjr3mIz67G9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-w4dpKtjr3mIz67G9 .cluster text{fill:#333;}#mermaid-svg-w4dpKtjr3mIz67G9 .cluster span{color:#333;}#mermaid-svg-w4dpKtjr3mIz67G9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-w4dpKtjr3mIz67G9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-w4dpKtjr3mIz67G9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-w4dpKtjr3mIz67G9 .icon-shape,#mermaid-svg-w4dpKtjr3mIz67G9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w4dpKtjr3mIz67G9 .icon-shape p,#mermaid-svg-w4dpKtjr3mIz67G9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-w4dpKtjr3mIz67G9 .icon-shape .label rect,#mermaid-svg-w4dpKtjr3mIz67G9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w4dpKtjr3mIz67G9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-w4dpKtjr3mIz67G9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-w4dpKtjr3mIz67G9 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Worker 节点

    Head 节点 · 生产/主控

    CX7 直连 · RoCE · 单口约 99 Gb/sMTU 两端必须一致

    GB10 · 128GB 统一内存

    fabric 网卡 enp1s0f1np1192.168.101.10

    管理网卡(有线)

    服务端口 8000 / 8081

    GB10 · 128GB 统一内存

    fabric 网卡 enp1s0f1np1192.168.101.11

    管理网卡(WiFi)

    内网管理链路SSH · 镜像/权重分发

    GID 自动探测脚本(写进两端启动脚本,避免硬编码漂移导致的建链失败):

    for i in $(seq 0 15); do
    t=$(cat /sys/class/infiniband/rocep1s0f1/ports/1/gid_attrs/types/$i 2>/dev/null || true)
    g=$(cat /sys/class/infiniband/rocep1s0f1/ports/1/gids/$i 2>/dev/null || true)
    if [ "$t" = "RoCE v2" ] && [ -n "$g" ]; then
    case "$g" in *ffff:*) NCCL_GID_INDEX=$i; break;; esac
    fi
    done

    链路验证命令:

    # 1. RoCE 设备状态(两端 ACTIVE)
    rdma link && ibdev2netdev

    # 2. RDMA 带宽实测(应接近 100 Gb/s / 单逻辑口)
    ib_write_bw 192.168.101.11 -d rocep1s0f1 –report_gbits -q 4 -R –force-link IB

    # 3. MTU 一致性
    ip link show enp1s0f1np1 | head -1
    ping -M do -s 8972 -c 3 192.168.101.11 # 计划用 9000 MTU 时先验证不丢包

    # 4. 关键:确认 NCCL 真的走了 IB,而不是静默退化为 TCP
    # 容器日志中应有 NET/IB 字样;缺失则 /dev/infiniband 未透传(需 –privileged)

    实测数据:ib_write_bw 4 QP 平均 99.37 Gb/s(单逻辑口,QP-MTU 4096)。要跑满 200G 需第二逻辑口配 IP + 双 HCA(NCCL_IB_HCA=rocep1s0f1,roceP2p1s0f1)。

    为什么反复强调通信层? 社区案例显示:容器缺 /dev/infiniband 时 NCCL 会无任何报错地退化为 TCP,带宽从 ~9.8 GB/s 掉到 ~2.1 GB/s,推理吞吐 65.4 → 34.6 tok/s。这个坑不看 NCCL_DEBUG=INFO 根本发现不了。


    3. 第一段:Qwen3.8-27B 单机生产部署与优化(SGLang)

    3.1 生产配置

    项目值
    引擎 SGLang(自构建镜像,DFlash2 已并入上游)
    主模型 RadixArk/Qwen3.8-27B-NVFP4(约 21 GB)
    投机草稿 z-lab/Qwen3.8-27B-DFlash2(约 3.6 GB,无损投机)
    上下文 262,144(256K,模型原生)
    KV Cache fp8_e4m3
    显存比例 –mem-fraction-static 0.50
    并发上限 –max-running-requests 8
    服务 8000 端口,OpenAI 兼容,无鉴权(内网直连)

    启动命令(核心参数):

    docker run -d –name qwen38-sglang-single –restart unless-stopped –gpus all \\
    –memory 100g –memory-swap 100g –shm-size 16g –network host –ipc=host \\
    -e TORCHINDUCTOR_CACHE_DIR=/cache/inductor -e HF_HUB_OFFLINE=1 \\
    -e SGLANG_OPT_MAMBA_SKIP_DECODE_LOCK=1 \\
    -v /home/spark/.config/qwen38/sglang-cache:/cache \\
    -v /home/spark/.cache/huggingface:/root/.cache/huggingface \\
    -v /home/spark/.config/qwen38:/out \\
    qwen38-dflash2:v1.2.3 python3 -m sglang.launch_server \\
    –tp-size 1 –context-length 262144 –mem-fraction-static 0.50 \\
    –host 0.0.0.0 –port 8000

    3.2 两个有效的优化项(实测有效)

    (1)权重加载 I/O 优化:GB10 是统一内存,mmap 随机读 4KB 页会拖慢加载,且 page cache 会挤占 KV 池。加两个 SGLang 参数:

    –weight-loader-prefetch-checkpoints # 4 线程顺序预读 checkpoint 进 page cache
    –weight-loader-drop-cache-after-load # 加载完丢弃 page cache,归还约 24GB 给系统

    (2)mamba 解码免锁:Qwen3.8 是 mamba 混合架构,大 prompt 场景曾出现挂起,环境变量 SGLANG_OPT_MAMBA_SKIP_DECODE_LOCK=1 消除该问题。

    优化前后对比(实测):

    指标优化前优化后变化
    权重加载(主模型) 141.5 s 107.0 s -24%
    权重加载(含 draft) 170.4 s 126.1 s -26%
    引擎启动总计 427.2 s 379.3 s -11%
    加载后系统 buff/cache 33 GB 9 GB -24 GB
    KV 池容量 413,280 tok 406,553 tok 持平(噪声内)

    3.3 性能与质量基线

    指标实测
    短提示解码(greedy 中位) 56.0 tok/s
    32K 长上下文解码 34–38 tok/s(受内容相关接受率影响,波动大)
    TTFT(短提示) 0.205 s
    长上下文检索 30K / 60K 深度 needle 精确取回(15.0 s / 29.2 s)
    质量探针 已知答案 6/6 通过;tool-call 解析正常

    经验:投机解码(DFLASH2)的接受率高度依赖内容类型——code 最高、散文最低,因此"同一模型不同负载"的吞吐差异可达 2 倍,做基准测试必须按负载类型分桶。


    4. 第二段:Qwen3.8-27B 双机 TP=2 验证(SGLang)

    4.1 双机能带来什么:先看社区数据

    工作负载(单流)1× Spark2× Spark (TP=2)
    Code 生成 52–61 tok/s 87 tok/s
    Prose 26 41
    Thinking 对话 34–49 49
    Prefill — 约 10K tok/s
    8 并发聚合 135–148 tok/s 134–148 tok/s(持平)

    结论直言:双机是 1.4–1.6x 而非 2x,收益集中在单请求吞吐与并发余量;如果是纯高并发场景,单机 DP + 网关负载均衡可能更划算。

    4.2 三条技术路线怎么选

    路线代表评价
    A. SGLang 手工双机 –tp 2 –nnodes 2 –node-rank 0/1 –dist-init-addr 社区双机主流、实测最优,推荐
    B. eugr 编排 spark-vllm-docker 的 run-recipe.sh 自动配 rank,手工全 hang 时它能通
    C. vLLM + Ray 官方 playbook 官方支持但实测吞吐约为 SGLang 一半

    4.3 双机八大坑(浓缩版)

    现象原因处理
    Worker 崩溃循环 DistNetworkError 对端未就绪 / 建链失败 严格先 Worker 后 Head
    NCCL 静默 hang 无报错 绑定了多 IP 网卡抓错 IP / MTU 两端不一致 控制面指向单一 IP 网卡;统一 MTU
    ibv_modify_qp EINVAL,一侧起不来 GID index 硬编码,重启后漂移 启动时自动探测 RoCEv2 IPv4 GID
    吞吐只有单机水平 NCCL 静默走了 TCP –privileged 透传 /dev/infiniband;NCCL_DEBUG=INFO 对拍
    参数不一致导致死锁 两 rank 参数必须逐字节一致 同一脚本、仅 –node-rank 不同
    max_tokens ≤ 8 请求打挂全集群 DFlash2 draft=8 边界缺陷 客户端约定不发 ≤8;或补丁把 <16 钳到 16
    客户端中断流请求导致崩溃 投机解码 async generator 边界 –watchdog-timeout 120 + cron 自愈
    重启要 6–8 分钟 权重重载 + CUDA graph 捕获 接受现实,用自愈守护把"死集群"变成"几分钟抖动"

    4.4 停机窗口实测结果

    三轮配置迭代后的最终数据(NVFP4 + DFlash2 + FP8 KV,512K 上下文):

    场景实测对照
    单流 code / math 52.0 / 54.7 tok/s 单机基线 54.8 / 58.5(持平)
    单流 prose 23.7 tok/s 单机 ~26(略低)
    code c4 聚合 163.5 tok/s —
    code c8 聚合 198.3 tok/s 单机 8 并发 135–148
    服务端批次峰值 251.6 tok/s(接受率 0.48) —

    跨节点通信全程确认 NET/IB,CUDA graph 生效。

    最终决策:维持单机生产。TP=2 功能验证通过、code 高并发有 +35–45% 收益,但需额外承担崩溃防护、端口切换与运维复杂度;TP=2 栈保留为已验证的备用/扩容路径。


    5. 第三段:DeepSeek-V4-Flash-0731 双机部署(vLLM TP=2)

    5.1 模型与栈

    项目值
    模型 deepseek-ai/DeepSeek-V4-Flash-0731
    架构 284B 总参 / 13B 激活 MoE,43 层,256 路由专家 + 1 共享(每 token 激活 6 个)
    精度 FP4 专家 + FP8 其余(预训练即混合精度,检查点 156 GB / 48 分片)
    投机解码 DSpark(模型内置 Markov 头,配置中 dspark_markov_rank 256)
    上下文 原生 1,048,576(YaRN factor 16)
    引擎 vLLM 定制镜像(eugr/spark-vllm-b12x,B12X 内核,面向 SM121)
    并行 TP=2 + –nnodes 2(launcher 的多机 no-Ray 模式)
    服务 8000 端口,模型名 DeepSeek-V4-Flash

    推理架构与数据流:

    #mermaid-svg-j6U4HAQS1XXVfKYF{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-j6U4HAQS1XXVfKYF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-j6U4HAQS1XXVfKYF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-j6U4HAQS1XXVfKYF .error-icon{fill:#552222;}#mermaid-svg-j6U4HAQS1XXVfKYF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-j6U4HAQS1XXVfKYF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-j6U4HAQS1XXVfKYF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-j6U4HAQS1XXVfKYF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-j6U4HAQS1XXVfKYF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-j6U4HAQS1XXVfKYF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-j6U4HAQS1XXVfKYF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-j6U4HAQS1XXVfKYF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-j6U4HAQS1XXVfKYF .marker.cross{stroke:#333333;}#mermaid-svg-j6U4HAQS1XXVfKYF svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-j6U4HAQS1XXVfKYF p{margin:0;}#mermaid-svg-j6U4HAQS1XXVfKYF .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-j6U4HAQS1XXVfKYF .cluster-label text{fill:#333;}#mermaid-svg-j6U4HAQS1XXVfKYF .cluster-label span{color:#333;}#mermaid-svg-j6U4HAQS1XXVfKYF .cluster-label span p{background-color:transparent;}#mermaid-svg-j6U4HAQS1XXVfKYF .label text,#mermaid-svg-j6U4HAQS1XXVfKYF span{fill:#333;color:#333;}#mermaid-svg-j6U4HAQS1XXVfKYF .node rect,#mermaid-svg-j6U4HAQS1XXVfKYF .node circle,#mermaid-svg-j6U4HAQS1XXVfKYF .node ellipse,#mermaid-svg-j6U4HAQS1XXVfKYF .node polygon,#mermaid-svg-j6U4HAQS1XXVfKYF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-j6U4HAQS1XXVfKYF .rough-node .label text,#mermaid-svg-j6U4HAQS1XXVfKYF .node .label text,#mermaid-svg-j6U4HAQS1XXVfKYF .image-shape .label,#mermaid-svg-j6U4HAQS1XXVfKYF .icon-shape .label{text-anchor:middle;}#mermaid-svg-j6U4HAQS1XXVfKYF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-j6U4HAQS1XXVfKYF .rough-node .label,#mermaid-svg-j6U4HAQS1XXVfKYF .node .label,#mermaid-svg-j6U4HAQS1XXVfKYF .image-shape .label,#mermaid-svg-j6U4HAQS1XXVfKYF .icon-shape .label{text-align:center;}#mermaid-svg-j6U4HAQS1XXVfKYF .node.clickable{cursor:pointer;}#mermaid-svg-j6U4HAQS1XXVfKYF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-j6U4HAQS1XXVfKYF .arrowheadPath{fill:#333333;}#mermaid-svg-j6U4HAQS1XXVfKYF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-j6U4HAQS1XXVfKYF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-j6U4HAQS1XXVfKYF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-j6U4HAQS1XXVfKYF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-j6U4HAQS1XXVfKYF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-j6U4HAQS1XXVfKYF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-j6U4HAQS1XXVfKYF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-j6U4HAQS1XXVfKYF .cluster text{fill:#333;}#mermaid-svg-j6U4HAQS1XXVfKYF .cluster span{color:#333;}#mermaid-svg-j6U4HAQS1XXVfKYF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-j6U4HAQS1XXVfKYF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-j6U4HAQS1XXVfKYF rect.text{fill:none;stroke-width:0;}#mermaid-svg-j6U4HAQS1XXVfKYF .icon-shape,#mermaid-svg-j6U4HAQS1XXVfKYF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-j6U4HAQS1XXVfKYF .icon-shape p,#mermaid-svg-j6U4HAQS1XXVfKYF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-j6U4HAQS1XXVfKYF .icon-shape .label rect,#mermaid-svg-j6U4HAQS1XXVfKYF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-j6U4HAQS1XXVfKYF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-j6U4HAQS1XXVfKYF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-j6U4HAQS1XXVfKYF :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    TP=2 集合通信RoCE NET/IB(占用 <2%)

    客户端OpenAI 兼容请求

    Head · APIServer :8000

    EngineCore rank0权重分片约 78GB

    Worker · EngineCore rank1权重分片约 78GB

    KV 池 fp8_ds_mla57万+ tokens / 256K 上下文

    DSpark 投机解码内置 Markov 头 · n=3

    流式输出短提示约 73 tok/s

    5.2 镜像获取的坑(docker 代理失效)

    问题根因处置
    docker pull 全部失败(EOF 重试) docker daemon 配了已失效的本地代理,且 registry 被污染解析 自研 OCI 拉取脚本走 docker.m.daocloud.io 镜像源直连(单流 6.1 MB/s,4 并发 ~75 MB/s),docker load 导入
    Worker 无法拉取镜像 镜像源对 Worker 不可达 Head docker save 后经 CX7 分发

    5.3 两套配置与实测性能

    # 配置A:200K 上下文 + fp8_ds_mla KV + DSpark
    ./run-recipe.sh recipes/deepseek-v4-flash-0731.yaml \\
    –max-model-len 200000 –gpu-mem 0.85 -e HF_HUB_OFFLINE=1 -d

    # 配置B:1M 上下文 + DSpark(关闭 CUDA graph 内存估算以最大化 KV 池)
    ./run-recipe.sh recipes/deepseek-v4-flash-0731.yaml \\
    –max-model-len 1000000 –gpu-mem 0.88 –max-cudagraph-capture-size 16 \\
    -e HF_HUB_OFFLINE=1 -e VLLM_MEMORY_PROFILER_ESTIMATE_CUDAGRAPHS=0 -d

    启动耗时:权重加载约 76 s(InstantTensor 快速加载)、CUDA graph 捕获约 25 s,从启动到 API 就绪约 5 分钟。

    配置 A(200K / 350,026 tokens KV 池):

    探针并发1并发2(聚合)并发4(聚合)
    code 解码 53.7 tok/s 72.1 121.4
    prose 解码 37.4 48.1 78.1
    TTFT 0.33–0.65 s 0.67–3.45 s 0.65–1.18 s

    长上下文:60K/120K/180K 深度 needle 6/6 通过(180K 预填 128–163 s,约 1.2K tok/s)。

    配置 B(1M / 1,774,482 tokens KV 池):

    探针并发1并发2(聚合)并发4
    code 解码 72.9 tok/s 95.7 56.1(单流降至 14.4)
    prose 解码 38.3 52.5 37.1
    检索深度结果预填耗时
    250,000 精确检索 OK 131.8 s
    600,000 精确检索 OK 403.1 s
    950,000 精确检索 OK 885.7 s

    注意:并发 4 时吞吐显著退化,原因是投机解码在 decode 阶段的验证批次膨胀(num_speculative_tokens=5),生产建议并发 ≤2。

    5.4 三个栈限制(实测确认,非配置问题)

    需求实际状态原因
    NVFP4 KV(nvfp4_ds_mla) 不可用 镜像内校验要求 GLM5Next/GLM-5.2 架构;DeepSeek-V4 走 fp8_ds_mla
    MTP 投机(method=mtp) 不可用 检查点草稿键为 mtp.{0..n}.*,经典 MTP 加载器按 model.layers.{N}.* 取键 → KeyError;DSpark 是唯一可用投机路径
    Decode Context Parallel(DCP) 不可用 NotImplementedError: B12X compressed sparse MLA does not support DCP

    6. 性能深挖:压测、利用率与调参(本文独家数据)

    生产切到 256K 配置后,我们做了一组系统性测试。

    6.1 KV 池并发压测(冷启动,每请求独立长提示)

    方法:流式请求 + 每 2 秒采样 /metrics(KV 占用、排队数),提示词每次随机生成以杜绝前缀缓存干扰。

    32K 提示:

    并发TTFT单流解码预填聚合排队峰值KV 峰值
    1 14.1 s 29.8 tok/s 1,883 tok/s 0 35.8%
    2 21.6 s 12.7 2,115 1 36.6%
    4 36.3 s 3.9 2,102 3 38.2%
    8 63.4 s 1.9 2,198 7 40.5%

    128K 提示:

    并发TTFT单流解码预填聚合排队峰值KV 峰值
    1 59.7 s 27.2 tok/s 2,092 tok/s 0 37.8%
    2 90.4 s 11.3 2,143 1 40.5%
    4 150.4 s 1.5 2,175 3 43.2%

    三个结论:

  • KV 池不是瓶颈:8×32K 只占 40%、4×128K 占 43%——容量上限约 9–10 路 128K 并发,远超算力所能服务的水位;
  • 瓶颈是预填算力:聚合预填恒定 ~2.1–2.2K tok/s,并发增加不提升总吞吐,只带来排队(waiting 从并发 2 起出现)与 TTFT 线性膨胀;
  • 单流解码随并发衰减(29.8→1.9 tok/s),长文交互建议并发控制在 2–3 路。
  • 6.2 意外发现:prefix cache 能扛 10 小时

    对照实验里,我们用了与 10 小时前完全相同的提示词:32K 的 TTFT 从 14 s 降到 0.69 s,128K 从 60 s 降到 0.97 s。该实例的 KV 缓存跨小时保留了长文档块。业务启示:固定系统提示 / 固定文档前缀的场景,长文 TTFT 是亚秒级——这是长文场景零成本的最大提速手段。

    6.3 硬件利用率实测:95% 却只烧 42W

    阶段Head GPUWorker GPU功耗SM 时钟RoCE 互联
    空闲 0% 0% 11.6 W 2411 MHz 0
    解码(生成 238 token) 94.8% 94.8% 29.7 W 2409 MHz 0.07 GB/s
    长文预填(64K) 95.8% 93.4% 42.2 W 2397 MHz 0.60 GB/s(链路 2%)

    解读:GPU 利用率接近 100% 但功耗极低——典型的内存带宽瓶颈特征:SM 显示"忙",其实在等数据。GB10 的 LPDDR5X 带宽(273 GB/s)只有 H100 HBM(3.35 TB/s)的约 1/12,而 MoE 推理是带宽敏感负载。

    定量验证:13B 激活 × ~0.5 字节 ≈ 每节点每 token 约 3.6 GB 权重流量 → 273 GB/s 的理论天花板约 75 tok/s,实测短上下文 73 tok/s,已到带宽的 93%+。而且双机互联完全不是瓶颈(TP 通信只占 RoCE 链路 2% 以下)。

    6.4 调参 A/B:max-num-batched-tokens 8192 vs 16384(反面教材)

    场景8192(默认)16384判定
    32K 提示 TTFT 14.1 s 43.2 s 劣化 3 倍
    128K 提示 TTFT 59.7 s 70.7 s 劣化
    KV 池 674,512 279,228(-59%) 劣化
    峰值激活内存 2.36 GiB 3.78 GiB 代价

    结论:批预算翻倍换不来预填收益,反而压缩 KV 池,此路不通,保持 8192。

    6.5 稳定性:投机解码深度 5 → 3 治好了"挂死"

    现象:num_speculative_tokens=5 时,长生成请求偶发 worker 挂死——生成速率突然归零 → 连续报"引擎 60 秒无输出" → 约 4 分钟后 RPC call to sample_tokens timed out → 引擎自毁,客户端收到 500。一晚复现两次。

    #mermaid-svg-AvY99lnDMpX6q7Lm{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AvY99lnDMpX6q7Lm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AvY99lnDMpX6q7Lm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AvY99lnDMpX6q7Lm .error-icon{fill:#552222;}#mermaid-svg-AvY99lnDMpX6q7Lm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AvY99lnDMpX6q7Lm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AvY99lnDMpX6q7Lm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AvY99lnDMpX6q7Lm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AvY99lnDMpX6q7Lm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AvY99lnDMpX6q7Lm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AvY99lnDMpX6q7Lm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AvY99lnDMpX6q7Lm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AvY99lnDMpX6q7Lm .marker.cross{stroke:#333333;}#mermaid-svg-AvY99lnDMpX6q7Lm svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AvY99lnDMpX6q7Lm p{margin:0;}#mermaid-svg-AvY99lnDMpX6q7Lm .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-AvY99lnDMpX6q7Lm .cluster-label text{fill:#333;}#mermaid-svg-AvY99lnDMpX6q7Lm .cluster-label span{color:#333;}#mermaid-svg-AvY99lnDMpX6q7Lm .cluster-label span p{background-color:transparent;}#mermaid-svg-AvY99lnDMpX6q7Lm .label text,#mermaid-svg-AvY99lnDMpX6q7Lm span{fill:#333;color:#333;}#mermaid-svg-AvY99lnDMpX6q7Lm .node rect,#mermaid-svg-AvY99lnDMpX6q7Lm .node circle,#mermaid-svg-AvY99lnDMpX6q7Lm .node ellipse,#mermaid-svg-AvY99lnDMpX6q7Lm .node polygon,#mermaid-svg-AvY99lnDMpX6q7Lm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AvY99lnDMpX6q7Lm .rough-node .label text,#mermaid-svg-AvY99lnDMpX6q7Lm .node .label text,#mermaid-svg-AvY99lnDMpX6q7Lm .image-shape .label,#mermaid-svg-AvY99lnDMpX6q7Lm .icon-shape .label{text-anchor:middle;}#mermaid-svg-AvY99lnDMpX6q7Lm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AvY99lnDMpX6q7Lm .rough-node .label,#mermaid-svg-AvY99lnDMpX6q7Lm .node .label,#mermaid-svg-AvY99lnDMpX6q7Lm .image-shape .label,#mermaid-svg-AvY99lnDMpX6q7Lm .icon-shape .label{text-align:center;}#mermaid-svg-AvY99lnDMpX6q7Lm .node.clickable{cursor:pointer;}#mermaid-svg-AvY99lnDMpX6q7Lm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-AvY99lnDMpX6q7Lm .arrowheadPath{fill:#333333;}#mermaid-svg-AvY99lnDMpX6q7Lm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AvY99lnDMpX6q7Lm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AvY99lnDMpX6q7Lm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AvY99lnDMpX6q7Lm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-AvY99lnDMpX6q7Lm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AvY99lnDMpX6q7Lm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-AvY99lnDMpX6q7Lm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AvY99lnDMpX6q7Lm .cluster text{fill:#333;}#mermaid-svg-AvY99lnDMpX6q7Lm .cluster span{color:#333;}#mermaid-svg-AvY99lnDMpX6q7Lm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AvY99lnDMpX6q7Lm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-AvY99lnDMpX6q7Lm rect.text{fill:none;stroke-width:0;}#mermaid-svg-AvY99lnDMpX6q7Lm .icon-shape,#mermaid-svg-AvY99lnDMpX6q7Lm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AvY99lnDMpX6q7Lm .icon-shape p,#mermaid-svg-AvY99lnDMpX6q7Lm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-AvY99lnDMpX6q7Lm .icon-shape .label rect,#mermaid-svg-AvY99lnDMpX6q7Lm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AvY99lnDMpX6q7Lm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AvY99lnDMpX6q7Lm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AvY99lnDMpX6q7Lm :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    长生成请求n=5 投机解码

    生成速率突然归零worker 挂死

    连续告警引擎 60s 无输出

    约 4 分钟后RPC sample_tokens 超时

    EngineDeadError客户端收到 500

    处置:投机深度 5 → 3

    10 小时 / 117 次请求0 错误 0 挂死

    处置:投机深度降到 3 后,连续 10 小时、117 次真实请求 0 错误、0 挂死。代价是吞吐略降;若追求极限速度可调回 5,但要接受挂死风险。

    6.6 顺带辟谣:换 NVFP4 权重不是免费午餐

    很多人(包括我们最初)以为"换 NVFP4 权重 = 带宽减半 = 速度翻倍"。核实后发现:

    • 官方 0731 检查点的专家层本来就是 FP4(FP4 专家 + FP8 其余),换 NVIDIA 的 nvidia/DeepSeek-V4-Flash-NVFP4(168 GB,ModelOpt 再量化)并不会减小权重体积;
    • 解码已贴着 273 GB/s 的带宽天花板(见 6.3),换任何 4-bit 格式都突破不了物理带宽;
    • 且该变体不支持 FP8 专属的 deep_gemm_mega_moe 内核,MoE 要走默认后端,可能反而更慢。

    7. 运维要点与踩坑清单

    7.1 常用运维命令

    # 实时滚动日志(双机合并,带节点前缀)
    { docker logs -f –tail 50 vllm_node 2>&1 | sed 's/^/[head] /' & \\
    ssh spark@192.168.101.11 'docker logs -f –tail 50 vllm_node 2>&1' | sed 's/^/[worker] /' & wait; }

    # 只看错误信号
    docker logs -f vllm_node 2>&1 | grep -E –line-buffered "ERROR|Traceback|EngineDeadError|500"

    # 实时负载(KV 占用 / 排队 / 运行中请求)
    watch -n 2 "curl -s http://127.0.0.1:8000/metrics | grep -E 'num_requests_(running|waiting)|kv_cache_usage_perc'"

    # 就绪判断:容器 Up ≠ 服务可用,必须等健康检查通过(大模型加载需数分钟)
    curl -s -o /dev/null -w '%{http_code}\\n' http://127.0.0.1:8000/health

    7.2 高频故障速查

    现象排查顺序
    端口不可达 容器 Up?→ 端口监听?→ 本机回环 → 外部连通性/防火墙
    启动慢/疑似卡住 首次 7–9 分钟、常规 5–7 分钟属正常;用 docker logs -f 看进度(权重加载→图捕获→就绪)
    客户端报 500 查引擎是否 EngineDeadError(见 6.5 挂死链),确认后重启服务
    客户端报模型不存在 请求体 model 必须与 –served-model-name 完全一致
    OOM / 系统换页 UMA 下权重+KV+系统共享 128GB;mem-fraction 取 0.5–0.9 区间实测,勿盲目调高(社区有 0.95 整机硬重启案例)
    想切回另一个模型 双机服务与单机服务互斥(都占满统一内存):先 docker rm -f 当前服务,再启动另一个

    7.3 GB10 统一内存注意事项

    • nvidia-smi 查不到显存占用、cudaMemGetInfo 数值失真——以容器内日志与实测为准;
    • 权重加载后会残留大量 page cache,会挤占 KV 池,建议用引擎的 drop-cache 选项(见 3.2)主动归还;
    • 容器内存上限(如 –memory 100g)与 gpu-memory-utilization 要一起算账,否则会触发 OOM 或被系统换页拖慢。

    8. 结论与选型建议

    8.1 一句话结论

    • 单机 Qwen3.8-27B:短提示 56 tok/s、256K 上下文,稳定承担日常生产;优化项(加载 I/O、mamba 免锁)实测有效;
    • 双机 Qwen3.8-27B(TP=2):功能验证通过,code 高并发 +35–45%,但单流无增益(1.4–1.6x 上限),列装为备用/扩容路径;
    • 双机 DeepSeek-V4-Flash-0731:284B MoE 跑通,短提示 73 tok/s、1M 上下文长文检索通过,是当前双机的"重载主力";
    • 硬件天花板:GPU 利用率 95%、功耗 42W、解码触及 273 GB/s 带宽上限——参数层面已无优化空间,瓶颈在 GB10 的 LPDDR5X 带宽。

    8.2 选型建议表

    场景建议
    日常对话/轻量 agent 单机 30B 级(Qwen3.8-27B)
    重载编程/长文档分析 双机 DeepSeek-V4-Flash(256K–1M)
    高并发 code 场景 双机 Qwen3.8 TP=2(c8 聚合 198 tok/s)或单机多实例+负载均衡
    长文交互 并发 ≤2–3;复用固定前缀吃 prefix cache(TTFT 秒级)
    想再提速 优先排查前缀复用与并发策略;权重格式/调参已无空间

    8.3 三条最重要的工程经验

  • 双机 ≠ 2x:收益集中在单请求打宽与并发余量,通信层配置(GID/MTU/IB 透传/启动顺序)决定成败;
  • 一切以冷启动实测为准:前缀缓存会让"看起来的 TTFT"虚假变快(我们实测从 60 s 到 0.7 s),做基准必须用独立随机提示词;
  • 先算带宽账再谈优化:激活参数 × 每参数字节 ÷ 内存带宽 就是解码上限,调参只能在逼近这个上限的路上走。

  • 9. 参考资料

    官方文档与工具:

    • Connect Two Sparks Playbook(NVIDIA 官方组网指南)
    • DGX Spark Clustering / ConnectX-7 网络
    • SGLang Server Arguments
    • vLLM Parallelism and Scaling
    • spark-vllm-docker(eugr,含 DeepSeek-V4-Flash 双机 recipe)

    社区实测(本文引用的对比数据来源,均已标注):

    • Qwen3.8-27B (NVFP4) on Single/Dual DGX Spark — SGLang + DFlash2
    • 4× DGX Spark Qwen3.8-27B + 8 pitfalls
    • Comprehensive Qwen3.8-27B Study on DGX Sparks
    • DeepSeek V4 Flash on two GB10 nodes — tuning and benchmark notes
    • RoCE 2× Inference Throughput(NCCL 静默退化 TCP 案例)

    免责声明:本文性能数据为在特定硬件(2× DGX Spark GB10)、特定软件版本下的实测结果,不同环境(内核、驱动、镜像版本)可能有差异;社区引用数据已在文中标注来源,仅供对比参考。

    完

    赞(0)
    未经允许不得转载:171主机测评 » DGX Spark GB10 双机实战:从 Qwen3.8 -27B 单机优化到 DeepSeek-V4-Flash 双机 TP=2 部署与性能调优全记录
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址