第二章:集群硬件架构——计算节点、互联网络与存储系统

大家好,我是你们的老朋友。今天咱们聊聊集群硬件架构。说实话,很多搞AI训练的朋友,一开始都只盯着GPU型号看。但我要告诉你,真正决定集群性能的,往往是那些你看不见的“管道”和“骨架”。

我个人习惯把集群硬件拆成三块来看:计算节点怎么设计、数据怎么在节点间跑、数据怎么存。这三块缺一不可。你想想看,就算你手里有H100,但网络带宽不够,数据搬不动,那GPU不就是在干等着吗?

2.1 计算节点设计:CPU与GPU的“亲密关系”

计算节点,说白了就是一台服务器。但这不是普通的服务器。一台训练节点里,CPU和GPU的拓扑关系,直接决定了你的训练效率。

CPU与GPU的互联方式

目前主流的有两种:

  • PCIe直连:每个GPU通过PCIe 4.0/5.0 x16连接到CPU。优点是简单,缺点是带宽有限(PCIe 4.0 x16单向约32GB/s)。
  • NVLink桥接:GPU之间通过NVLink直接通信,带宽可达PCIe的5-10倍。NVIDIA的DGX系列就是典型。

我记得有一次帮客户排查性能问题。他们用的是8卡A100节点,但训练吞吐死活上不去。我一看拓扑,好家伙,GPU0和GPU7之间要走两跳PCIe,中间还得经过CPU。这就是典型的“跨NUMA访问”问题。

核心原则:尽量让数据在同一个NUMA域内流动。跨NUMA访问,延迟会翻倍,带宽会腰斩。

典型的8卡GPU拓扑

我画了一张图,帮你理解常见的8卡GPU拓扑结构:

CPU 0 CPU 1 GPU 0 GPU 1 GPU 2 GPU 3 GPU 4 GPU 5 GPU 6 NVSwitch CPU GPU (NUMA 0) GPU (NUMA 1) NVSwitch

这张图里,GPU 0-3挂在CPU 0下,GPU 4-7挂在CPU 1下。同组内的GPU通过NVLink全互联,跨组通信则要走NVSwitch。嗯,这里要注意:如果你的训练任务需要频繁跨组通信,那NVSwitch的带宽就成了瓶颈。

我的建议:在分配GPU给训练任务时,尽量让同一个任务的GPU落在同一个NUMA域内。可以用 nvidia-smi topo -m 命令查看拓扑。

2.2 高速互联网络:集群的“血管”

单机性能再强,也架不住模型太大。当模型参数超过单卡显存时,我们就需要多机并行训练。这时候,网络就是你的命脉。

三种主流互联技术

技术 带宽 延迟 适用场景
NVLink (NVIDIA) 900 GB/s (H100) ~0.5 μs 节点内GPU通信
InfiniBand (IB) 400 Gb/s (NDR) ~1 μs 节点间通信,HPC首选
RoCE (RDMA over Converged Ethernet) 200-400 Gb/s ~2-3 μs 成本敏感场景,兼容以太网

我个人在项目中更倾向于InfiniBand。为什么?因为它有原生的RDMA支持,CPU几乎不参与数据传输。我曾经在一个2000卡集群上做过对比,同样跑GPT-3训练,IB网络比RoCE快了将近15%。

避坑指南:我曾经遇到过一个客户,为了省钱用了RoCE。结果训练时网络抖动严重,每过几分钟就出现一次“all-reduce超时”。最后排查发现是交换机缓存太小,加上PFC流控配置不当。如果你非要用RoCE,记得把交换机的buffer调大,并且开启ECN(显式拥塞通知)。

网络拓扑设计

常见的网络拓扑有两种:

  • Fat-Tree(胖树):带宽逐层收敛,适合中小规模集群。我建议128节点以下用这个。
  • Dragonfly(蜻蜓):全互联,延迟低,适合超大规模集群。我见过最大的Dragonfly集群有上万节点。

你想想看,如果你的集群有1024个节点,用Fat-Tree需要多少层?答案是4层。每层带宽收敛比1:1,那成本就太高了。所以大集群基本都用Dragonfly。

2.3 存储架构:数据怎么喂给GPU

训练一个千亿参数模型,数据量轻松上TB甚至PB。怎么把这些数据高效地喂给GPU,是个大问题。

并行文件系统

目前主流的有两种:

  • Lustre:开源,性能强悍。我见过最大的Lustre集群有1000多个OST(对象存储目标),总带宽超过1TB/s。
  • GPFS(现在叫IBM Storage Scale):商业软件,稳定性好。很多金融、科研机构在用。

这两种系统都支持POSIX接口,也就是说,你可以像操作本地文件一样操作它们。但要注意,并行文件系统的元数据操作(比如ls、stat)很慢。我曾经见过一个团队,训练脚本里每轮迭代都去检查文件是否存在,结果90%的时间都花在了元数据操作上。

最佳实践:训练前把数据列表缓存到内存里,训练过程中不要频繁做文件系统元数据操作。用 tf.data 或 torch.utils.data 的缓存机制。

对象存储

对象存储(比如MinIO、Ceph RGW)是另一种选择。它不兼容POSIX,但扩展性极好,可以轻松扩展到EB级。我建议把对象存储作为“冷数据”层,存放原始数据集和模型checkpoint。训练时,先把数据从对象存储拉到本地SSD,再开始训练。

这里有个小技巧:很多团队直接用对象存储挂载到训练节点上,结果发现训练速度慢得像蜗牛。为什么?因为对象存储的延迟太高了(毫秒级),而GPU需要微秒级的数据供给。所以,永远不要直接训练对象存储上的数据。

存储类型 延迟 吞吐 扩展性 推荐用途
本地NVMe SSD ~10 μs ~7 GB/s 差(单机) 训练数据缓存
Lustre/GPFS ~100 μs ~100 GB/s (集群) 好(千节点) 共享数据集、checkpoint
对象存储 ~10 ms ~10 GB/s (集群) 极好(EB级) 冷数据归档、备份

好了,这一章的内容就到这里。记住,硬件架构是性能优化的基石。下一章我们会深入聊聊GPU的底层工作原理,包括SM架构、warp调度、内存层次结构。到时候我会分享一些我在CUDA编程中踩过的坑,保证让你少走弯路。

想要更多资料,联系可可