第二章:集群硬件架构——计算节点、互联网络与存储系统
大家好,我是你们的老朋友。今天咱们聊聊集群硬件架构。说实话,很多搞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拓扑结构:
这张图里,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编程中踩过的坑,保证让你少走弯路。
想要更多资料,联系可可