如果把 8 台 DGX Spark 连成一整个集群,真正的门槛不在拆箱和通电,而在于网络规划、并行策略、调度器配置和故障排查。单台 DGX Spark 是 NVIDIA 面向桌面实验室推出的 AI 超级计算机,核心是 Grace Blackwell 平台与 128GB 统一内存,适合在本地加载大模型;但当你把 8 台放在一个机架上,想统一做模型微调、推理服务或者多租户实验时,问题就从“能不能跑”变成“怎样让 8 台机器像一个人那样协同”。本文从工程视角拆解这套 8 台 DGX Spark 集群:先讲清楚单机能力、集群收益和并行选型,再给出 Kubernetes + NVIDIA GPU Operator 的搭建步骤,最后补上性能验证、常见故障和生产环境建议。无论你是刚拿到两台设备想做张量并行,还是已经在跑 8 台集群,都可以按顺序复现。
这里的“Spark”不是 Apache Spark,也不是大数据离线计算框架。NVIDIA DGX Spark 的产品命名偏“桌面级 AI 超算”,它不负责跑 Spark SQL,它负责的是大模型训练、微调、推理和原型验证。下面所有章节说的都是 GPU 集群,不是数据仓库集群。
1. 先理解 DGX Spark 单机能力,再判断 8 台集群是否值得组
1.1 DGX Spark 到底是一台怎样的设备
通俗地说,DGX Spark 是一台可以放在桌面或小车上的小型 AI 服务器。它不像传统 GPU 服务器那样需要两层机柜和 8 块大板卡,而是把 CPU、GPU、统一内存、网络和系统管理能力压缩进一个紧凑机身里。
技术定义上,DGX Spark 基于 NVIDIA Grace Blackwell 平台,采用 GB10 超级芯片。CPU 和 GPU 不再是主机板上分开的部件,而是在同一颗超级芯片上完成集成。它提供约 128GB 的统一内存,CPU 和 GPU 可以共同访问同一块内存区域。这种设计的核心价值是:大模型权重、KV Cache、激活值和框架运行时的临时数据都能放在同一块内存池里,减少 CPU 与 GPU 之间的数据搬运。
单台 DGX Spark 的官方宣传场景是“在本地运行可达 200B 参数级别的大模型”。这句话要正确理解:200B 参数模型通常需要量化、小批次、有限上下文,甚至需要牺牲一部分精度才能塞进统一内存。生产环境里的 200B 模型,配 64K 上下文、高并发请求、连续推理,单台设备会非常吃力。
还有一个容易误解的地方:统一内存不等于显存。你不能再像看普通 GPU 那样只看“显存 24GB”或“显存 48GB”,而要把 CPU 内存和 GPU 内存当成一个大池子统一规划。PyTorch 里torch.cuda.memory_summary()能看到 GPU 侧分配,但host侧的内存可能同样成为瓶颈。
1.2 用 8 台组集群,收益到底在哪里
8 台 DGX Spark 从纸面上看,统一内存总量接近 1TB。这意味着更大参数规模的模型可能被拆到多台机器上运行,多个团队或多个任务也可以并行跑在不同节点上。
但要注意:8 台设备不自动等价于“单台性能乘以 8”。跨节点通信要走网络,而网络带宽和延迟远不能和芯片内部的互连相比。如果把一个需要频繁同步的模型切分到 8 台机器上,通信往往会成为新的瓶颈。组集群的真正价值,是获得更大的内存池、更高的并发吞吐和更灵活的多任务调度能力。
下面这张表可以帮你先判断方向:
| 维度 | 单台 DGX Spark | 8 台 DGX Spark 集群 |
|---|---|---|
| 可用统一内存 | 约 128GB | 约 1TB(实际受网络和调度限制) |
| 典型工作负载 | 单模型推理、原型开发、轻量微调 | 多模型部署、多租户实验、更大模型并行 |
| 同时并发任务数 | 受单机内存和 GPU 资源限制 | 可按节点拆分,支持并行任务 |
| 跨节点通信 | 不需要 | 必需,通信质量直接影响性能 |
| 运维复杂度 | 低,当作一台高性能电脑管理 | 高,需处理集群调度、共享存储、监控、故障 |
| 故障影响范围 | 单台故障,任务失败 | 单节点故障可能导致分布式训练中断,需要恢复机制 |
如果你的需求只是“一个人跑一个 70B 量化模型”,单台 DGX Spark 或两台做简单数据并行很可能就够。如果你要同时跑多个模型、多人共享、定时批量实验,才值得组 8 台。
1.3 组集群前,先想清楚这台集群要跑什么
不同业务场景,对集群规划的要求差别很大。
第一种场景是本地大模型推理服务。目标是让 8 台机器提供稳定的 OpenAI 兼容接口。此类场景需要关注推理引擎的并行策略、请求路由、模型加载时长和 GPU 内存利用率。
第二种场景是多节点大模型训练或微调。8 台机器会组成一个分布式训练任务。此时重点是数据并行、流水线并行、检查点保存和失败恢复。网络带宽不足时,训练效率会非常明显地下滑。
第三种场景是团队 AI 开发平台。需要把 8 台设备当成资源池,通过 Kubernetes 给不同成员分配 GPU 配额,限制最大并发数,并提供统一日志和监控入口。这样即使有人误删 Pod,也不会影响整个集群。
在动手前,先确定你的核心场景。因为场景决定你买什么样的交换机、要不要配共享存储、要不要装训练算子,以及要不要搭一套高可用控制平面。没有场景就搭集群,最后只会得到一台“能启动但不知道用来干什么”的 8 节点实验环境。
2. 8 台 DGX Spark 组集群的前期规划:网络、存储和软件栈
2.1 网络规划是决定成败的第一项
多节点集群必须通信,而通信质量和网络强相关。DGX Spark 自带网络接口的速率,以及是否支持外接高速网卡,要以你手上硬件的具体型号和官方文档为准。这里更重要的是一套通用的网络规划思路。
先建一张规划表。8 台机器建议至少规划两类网络:
- 管理网络:用于 SSH、Kubernetes API、监控采集、系统更新。
- 数据网络:用于模型并行、梯度同步、数据集传输、镜像拉取。
如果条件允许,把两个网络分到不同物理链路或不同 VLAN。数据网络最好使用独立交换机,不要和办公室普通流量混在一起。
IP 规划示例:
| 主机名 | 管理 IP | 数据 IP | 角色 |
|---|---|---|---|
| dgx-spark-m01 | 192.168.10.11 | 192.168.50.11 | 控制面 |
| dgx-spark-w01 | 192.168.10.21 | 192.168.50.21 | Worker |
| dgx-spark-w02 | 192.168.10.22 | 192.168.50.22 | Worker |
| dgx-spark-w03 | 192.168.10.23 | 192.168.50.23 | Worker |
| dgx-spark-w04 | 192.168.10.24 | 192.168.50.24 | Worker |
| dgx-spark-w05 | 192.168.10.25 | 192.168.50.25 | Worker |
| dgx-spark-w06 | 192.168.10.26 | 192.168.50.26 | Worker |
| dgx-spark-w07 | 192.168.10.27 | 192.168.50.27 | Worker |
在正式部署前,至少要把管理 IP 写进/etc/hosts,让节点之间能通过主机名互访。实验环境可以不做 DNS;生产环境建议用内网 DNS,避免大规模集群靠 hosts 文件同步。
对于跨节点模型并行,10GbE 是第一道底线,但不代表 10GbE 一定够用。如果模型用张量并行,每一层都需要多次跨节点 all_reduce,通信量极大。若使用流水线并行,通信量相对小一些。所以网络选型要跟并行策略一起决定,而不是先把机器连起来再说。
2.2 存储:集群不能只有计算节点
8 台 DGX Spark 都有自己的本地硬盘,但如果每台机器都保存一份完整的模型权重、数据集和日志,会出现几个问题:
- 模型权重占用大量本地空间,且每一份升级都要同步 8 次。
- 微调产生的 checkpoint 散落在各节点,节点故障后难以恢复。
- 日志分散,排查问题时要登录多台机器。
常见的做法是引入共享存储。实验环境可以先用一台节点充当 NFS Server,把/data导出到所有节点。也可以部署 MinIO 作为对象存储,存放模型权重和数据集,训练任务运行时再拉取到本地缓存。
NFS 导出示例:
# 在存储节点执行 sudo mkdir -p /data/models /data/datasets /data/checkpoints sudo chmod 777 /data # 编辑 /etc/exports echo "/data 192.168.10.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports sudo exportfs -ra sudo systemctl restart nfs-server其他节点挂载示例:
sudo mkdir -p /mnt/dgx-data sudo mount -t nfs 192.168.10.11:/data /mnt/dgx-data # 写入 /etc/fstab echo "192.168.10.11:/data /mnt/dgx-data nfs defaults 0 0" | sudo tee -a /etc/fstab这里要注意:NFS 适合存放模型权重、数据集和 checkpoint,但不适合把训练日志直接高频写入 NFS。高并发小文件写入会拖慢整个存储。更合理的做法是:日志先在本地写,再异步同步到对象存储或日志系统。
如果实验环境不想引入复杂存储,可以先用“本地盘 + 脚本同步”的方式跑通,但要在文档里记录清楚数据在哪台机器。
2.3 软件栈版本要对齐,否则后面每一步都会踩坑
GPU 集群最怕版本错位。驱动版本、CUDA 版本、容器运行时版本、Kubernetes 版本、GPU Operator 版本、模型框架版本,任何一个环节不匹配,都可能出现“驱动已经装上,容器却看不到 GPU”这类问题。
一个相对稳定的软件栈规划如下:
| 组件 | 作用 | 版本建议 |
|---|---|---|
| DGX OS | 操作系统和 NVIDIA 原厂驱动基础 | 使用厂商出厂推荐版本,不要轻易升级到通用 Ubuntu |
| NVIDIA 驱动 | 驱动 GPU 和 CUDA 运行时 | 与 DGX OS 配套 |
| containerd | Kubernetes 容器运行时 | 使用 Kubernetes 官方支持版本 |
| Kubernetes | 集群调度平台 | 使用稳定版,避免过新或过旧 |
| NVIDIA GPU Operator | 自动管理驱动、运行时、device plugin 和监控 | 与 Kubernetes 版本兼容 |
| CUDA | 容器内计算框架基础 | 写在基础镜像内,跟随模型框架选择 |
| PyTorch / vLLM / NeMo | AI 负载 | 都放在容器镜像中,主机不直接安装 |
需要强调:DGX Spark 如果出厂已经安装了 NVIDIA 官方 DGX OS 和驱动,就不要为了“更新”而手动重装驱动。很多故障都出在“原本能用,升级后反而找不 GPU”的情况。
注意:DGX Spark 的“统一内存”和普通显卡的“显存”不同,不能只看设备显示的内存大小,还要考虑系统整体内存分配。部署大模型前,先在单机用
nvidia-smi、free -g和cat /proc/meminfo确认当前内存占用基线。
3. 从零开始搭建 8 节点 Kubernetes 加速集群
3.1 初始化前的基础配置
这里采用最小可用方案:1 个控制面节点 + 7 个 Worker 节点。生产环境如果在意控制面高可用,可以扩展到 3 个控制面节点,但会多出 etcd 和负载均衡配置,实验阶段先用单控制面跑通。
在所有 8 台机器上执行基础配置。
设置主机名,以控制面节点为例:
sudo hostnamectl set-hostname dgx-spark-m01安装常用工具并同步时间:
sudo apt update sudo apt install -y ntpdate sudo ntpdate cn.pool.ntp.org sudo timedatectl set-timezone Asia/Shanghai写入/etc/hosts,确保节点之间可以用主机名访问:
192.168.10.11 dgx-spark-m01 192.168.10.21 dgx-spark-w01 192.168.10.22 dgx-spark-w02 192.168.10.23 dgx-spark-w03 192.168.10.24 dgx-spark-w04 192.168.10.25 dgx-spark-w05 192.168.10.26 dgx-spark-w06 192.168.10.27 dgx-spark-w07加载内核模块并配置转发:
sudo modprobe overlay sudo modprobe br_netfilter cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF sudo sysctl --system这些配置不是随意加的。Kubernetes 的 Service、Pod 跨节点通信依赖 iptables 和 IP 转发,br_netfilter是为了让网桥流量也能被 iptables 规则处理。
3.2 用 kubeadm 初始化控制平面
在控制面节点安装 kubeadm、kubelet、kubectl。由于 Kubernetes 版本更新很快,这里不写死具体版本,建议先运行apt list -a kubeadm查看可用版本,选择一个稳定版本。
sudo apt install -y kubeadm kubelet kubectl初始化控制面。这里选择 Calico 作为网络插件,所以--pod-network-cidr要与 Calico 默认网段一致。如果你的内网网段已被其他系统占用,需要调整为不冲突的地址。
sudo kubeadm init \ --pod-network-cidr=10.244.0.0/16 \ --apiserver-advertise-address=192.168.10.11初始化完成后,按提示执行:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config接着安装 Calico CNI。具体版本以官方发布为准,这里给出通用命令:
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/calico.yaml然后查看节点状态:
kubectl get nodes此时控制面节点可能没有 Ready,因为操作系统的kubelet刚启动,需要等待一会儿。网络插件启动完成后,状态会变为 Ready。
Worker 节点加入集群使用kubeadm join命令。如果初始化时没有保存 join token,可以在控制面重新生成:
kubeadm token create --print-join-command在 Worker 上执行返回的命令。完成后在控制面确认:
kubectl get nodes -o wide如果所有节点均处于Ready,Kubernetes 控制面搭建就完成了。这一步是整个集群的骨架,后续 GPU 能力、存储挂载、模型调度都建立在它之上。
3.3 安装 NVIDIA GPU Operator,而不是手动每台装驱动
在很多入门教程里,大家习惯手工安装 NVIDIA 驱动,然后配置 Docker 的 nvidia-container-runtime。但 8 台机器逐个手工装驱动,效率低且容易漏版本。更好的做法是使用 NVIDIA GPU Operator,它通过 Kubernetes DaemonSet 在每台节点上自动安装和配置 GPU 运行环境。
安装 GPU Operator 前,先确认每台节点能否识别 GPU:
nvidia-smi如果控制面节点本身没有 GPU,也可以让 GPU Operator 只作用于 Worker 节点。对于 8 台 DGX Spark,建议默认在所有节点启用。
使用 Helm 安装:
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm repo update helm install gpu-operator nvidia/gpu-operator \ --namespace gpu-operator \ --create-namespace \ --set driver.enabled=false这里设置了driver.enabled=false,原因是你手上的 DGX Spark 很可能已经预装了官方驱动。如果 GPU Operator 再次自动安装驱动,可能与原厂驱动冲突。若你的设备是裸系统、没有 NVIDIA 驱动,再把driver.enabled改成true。
安装完成后,查看是否启动成功:
kubectl get pods -n gpu-operator kubectl describe nodes | grep -i nvidia如果节点上出现了类似nvidia.com/gpu: 1的资源,说明 GPU 资源已经上报给 Kubernetes。随后用一个小 Pod 验证:
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: nvidia-smi-test spec: restartPolicy: Never containers: - name: nvidia-smi image: nvidia/cuda:12.4.1-base-ubuntu22.04 command: ["nvidia-smi"] resources: limits: nvidia.com/gpu: 1 EOF kubectl logs nvidia-smi-test看到 NVIDIA 驱动信息后,删除测试 Pod:
kubectl delete pod nvidia-smi-test这一步完成,8 台机器已经在 Kubernetes 层具备了 GPU 调度能力。但距离“跑大模型”还差一步:多节点分布式任务不能简单靠单个 Pod 完成。
4. 让大模型真正跑在 8 台 DGX Spark 上:并行策略与调度
4.1 多机并行不是 Kubernetes 自动帮你完成的
Kubernetes 原生 GPU 调度目前只能解决“Pod 请求一块 GPU”和“Pod 请求两块 GPU”的问题。当你给一个 Pod 写limits: nvidia.com/gpu: 2时,调度器会尝试在一个节点上找到两块可用 GPU。它不会把一个 Pod 拆到两台机器上。
多机大模型任务需要拆成多个 Pod,每个 Pod 跑在各自的节点上,然后由分布式训练框架负责节点间通信。这类任务通常使用 PyTorchJob、MPIJob 或者 StatefulSet + Headless Service 来管理。
因此你会遇到两个新问题:
- Kubernetes 如何给多个 Pod 分配稳定的主机名和 IP?
- 分布式框架如何知道谁是 master、谁是 worker、如何建立通信?
解决这两个问题最简单的方式是 StatefulSet。StatefulSet 会为每个 Pod 生成固定名称,比如dist-worker-0、dist-worker-1,配合 Headless Service,Pod 之间可以通过dist-worker-0.dist-test这样的 DNS 名字互相访问。
4.2 用 StatefulSet 跑一个多节点通信验证任务
下面这段示例用来验证 8 节点之间的 PyTorch 分布式通信是否正常,不是完整训练代码。你需要把核心脚本做成镜像,或者在启动命令里动态执行。
先创建 Headless Service 和 StatefulSet:
apiVersion: v1 kind: Service metadata: name: dist-test spec: clusterIP: None selector: app: dist-test ports: - port: 23456 targetPort: 23456 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: dist-worker spec: serviceName: dist-test replicas: 8 selector: matchLabels: app: dist-test template: metadata: labels: app: dist-test spec: containers: - name: main image: pytorch/pytorch:2.3.1-cuda12.1-cudnn8-runtime command: ["sh", "-c"] args: - | python /workspace/dist_test.py \ --rank $(echo $HOSTNAME | awk -F'-' '{print $NF}') \ --master dist-test-0.dist-test env: - name: MASTER_ADDR value: dist-test-0.dist-test - name: MASTER_PORT value: "23456" - name: NCCL_DEBUG value: "INFO" - name: NCCL_SOCKET_IFNAME value: "eth0" resources: limits: nvidia.com/gpu: 1对应的 Python 脚本dist_test.py负责初始化 NCCL 并执行一次 all_reduce:
import argparse import time import torch import torch.distributed as dist parser = argparse.ArgumentParser() parser.add_argument("--rank", type=int, required=True) parser.add_argument("--master", type=str, required=True) args = parser.parse_args() dist.init_process_group( backend="nccl", init_method="tcp://{}:23456".format(args.master), rank=args.rank, world_size=8, ) tensor = torch.ones(256, dtype=torch.float32, device="cuda") dist.barrier() start = time.time() for _ in range(10): dist.all_reduce(tensor) torch.cuda.synchronize() elapsed = time.time() - start if dist.get_rank() == 0: print("all_reduce avg time: {:.4f}s".format(elapsed / 10)) dist.destroy_process_group()这个示例能帮你验证 DNS 解析、网络连通性、NCCL 协议是否可用。如果这里卡住,后面任何大模型训练和推理都跑不起来。
4.3 并行策略怎么选:张量并行、流水线并行、数据并行
8 台 DGX Spark 的并行策略是性能的关键。选错并行方式,可能比单机运行还慢。
| 并行方式 | 基本原理 | 跨节点通信量 | 适用场景 |
|---|---|---|---|
| 数据并行 | 每台节点加载相同模型,处理不同数据批次,定期同步梯度 | 通信量取决于梯度大小和同步频率 | 模型能塞进单机内存时,最常用 |
| 流水线并行 | 按 transformer 层切分,节点 0 负责前若干层,节点 1 负责后续层 | 通信量为中间激活值,相对稳定 | 模型很大,必须跨节点切分时优先考虑 |
| 张量并行 | 把每一层内的矩阵运算切到多个节点 | 通信量非常大,每层前向后向都要 all_reduce | 单机内多 GPU 更合适,跨节点需高速网络 |
| 专家并行 | MoE 模型把不同专家放到不同节点 | 需要 all-to-all 通信,延迟敏感 | 大规模 MoE 模型,网络要求极高 |
对于 8 台 DGX Spark,合理的做法通常是把数据并行和流水线并行组合使用。先把一个大模型按层切成几段,放到多个节点上;每个节点再复制一份模型段,处理不同数据。张量并行尽量只用在单节点内,如果强行跨 8 台,10GbE 网络会很难喂满 GPU。
注意:跨节点张量并行对网络带宽非常敏感。在正式训练前,先做一次小规模 all_reduce 测试;如果 128MB 张量的同步耗时明显高于预期,就不要在 8 台之间开大张量并行。
5. 怎么验证集群和模型性能而不是只看到“能启动”
5.1 用通信基准先量出网络水位
很多集群搭建完成后,跑模型能启动,但速度远低于预期。这往往不是 GPU 算力不够,而是跨节点通信没有达标。
在单机上跑 GPU 算例,瓶颈是 GPU 算力。在 8 台机器上跑分布式任务,瓶颈通常是网络延迟和带宽。你可以用简单的 PyTorch all_reduce 脚本来记录通信耗时。
更细的测试可以逐步增加张量体积:
| 张量大小 | 单次 all_reduce 耗时 | 说明 |
|---|---|---|
| 1 MB | 0.x ms | 检查通信延迟 |
| 128 MB | x ms | 检查带宽 |
| 1 GB | x ms | 接近大模型梯度同步场景 |
如果 128MB 的 all_reduce 耗时非常高,比如超过百毫秒级,就要检查网络配置。先看两端网卡速率:
ethtool eth0 | grep Speed再看是否有多条链路负载不均,最后看交换机端口是否有丢包:
netstat -i5.2 模型推理压测:吞吐、首 token 延迟和并发
如果是推理场景,建议先固定一组可复现的压测参数,然后记录结果,而不是只跑一次 curl