当 AI 训练从单机 GPU 扩展到多个节点时,平台团队面对的问题就不再只是“有没有足够的显卡”。节点之间的网络、数据读取、任务调度、故障恢复、可观测性和资源隔离,都会直接影响训练是否能稳定完成。
因此,给集群装上 GPU 驱动只是起点。真正的 AI-ready 平台,需要把一次分布式训练当成一个完整的云原生工作负载来设计。
多节点训练为什么会暴露平台短板
单节点训练失败时,排查范围通常比较集中:GPU 显存、驱动、模型代码或数据文件。但训练跨越多个节点后,新的瓶颈会同时出现:
- 网络成为训练路径的一部分:梯度同步、参数交换和检查点上传都会消耗带宽。节点之间延迟抖动时,最快的 GPU 也可能在等待最慢的节点。
- 数据访问决定 GPU 利用率:如果每个 worker 都从远程对象存储重复读取数据,训练可能变成“GPU 等数据”。
- 调度器需要理解拓扑和资源组合:训练任务通常需要一组同时可用的 GPU,而不是零散的 GPU 空闲容量。
- 失败成本随任务时长放大:运行数小时甚至数天的训练,如果没有检查点、重试策略和清晰的失败诊断,一次节点故障就可能让整个任务归零。
- 资源隔离不能只看 CPU 和内存:GPU 型号、显存大小、节点间网络、存储吞吐和 NUMA 拓扑都可能影响任务结果。
这些问题并不意味着所有平台都要一次性引入复杂系统。更实际的做法是,把训练工作负载拆成几个可验证的基础能力,并为每一项设定可观测指标。
一套可靠基础需要覆盖哪些层面
1. 资源层:不仅要“有 GPU”,还要知道 GPU 是什么
平台需要记录节点上的 GPU 型号、数量、显存、驱动和 CUDA 兼容性。调度策略则应避免把一个多节点任务分配到性能差异过大的节点集合中。
可以从以下问题开始检查:
- 训练任务申请的 GPU 是否真的来自同一类硬件?
- 节点是否有足够的 CPU 和内存支撑数据预处理?
- GPU 是否通过正确的 device plugin 暴露给容器?
- 节点升级或驱动变更后,是否能阻止不兼容任务被调度?
2. 网络层:把带宽、延迟和拓扑当作训练资源
分布式训练对网络的要求通常高于普通微服务。平台团队应区分管理网络、存储网络和训练通信网络,并在可行时为高吞吐训练提供专用或隔离的网络路径。
不要只测“节点能不能互相 ping 通”。更有价值的验证包括:
- 节点间带宽是否满足目标模型的通信需求;
- 高峰期延迟是否稳定;
- 容器网络是否允许训练框架使用所需端口;
- 节点故障或网络抖动时,任务是否能够被识别并终止,而不是无限等待。
3. 数据与检查点层:让训练可以重启,而不是只能祈祷
训练数据应尽量靠近计算节点,并采用适合大文件顺序读取的存储方案。对于频繁读取的小文件,通常需要在数据管道中做分片、打包或缓存,避免大量元数据请求拖慢训练。
检查点则应被视为平台能力,而不是训练脚本里的临时 save():
- 检查点路径应包含实验 ID、模型版本和数据版本;
- 写入过程要避免产生半成品文件;
- 训练任务重启时,应明确从哪个检查点恢复;
- 清理策略不能误删最近一次可恢复版本。
4. 调度与生命周期层:让任务成组运行、成组结束
分布式任务通常需要 gang scheduling 或等价的成组调度语义:只有当所需的 worker 数量和 GPU 都准备好时,任务才开始运行。否则,一个任务可能长期占用部分资源,同时等待剩余节点,造成集群碎片化。
生命周期管理也需要统一:任务提交、排队、启动、运行、失败、重试和清理,都应有明确状态。平台不应只显示一个“Pod Pending”,而应能帮助使用者判断究竟是 GPU 不足、镜像拉取失败、网络未就绪,还是节点不满足约束。
一个可改造的多节点训练启动示例
下面的例子假设:
- 使用 PyTorch Distributed;
- 已经有两个可通过网络互通的训练节点;
- 节点之间能够通过 SSH 执行命令;
- 每个节点有 8 张 GPU;
- 主节点地址为
10.0.0.10; - 容器、驱动和数据路径已经准备好。
这不是完整的 Kubernetes Operator 配置,但可以用来验证网络、端口和 rank 配置是否正确。将 train.py 换成自己的训练脚本即可:
#!/usr/bin/env bash
set -euo pipefail
MASTER_ADDR="10.0.0.10"
MASTER_PORT="29500"
NNODES=2
NPROC_PER_NODE=8
NODE_RANK="${NODE_RANK:?set NODE_RANK to 0 or 1}"
# 在每个节点执行;NODE_RANK=0 表示主节点,NODE_RANK=1 表示第二个节点。
# train.py 需要使用 torch.distributed.init_process_group 初始化进程组。
torchrun \
--nnodes="${NNODES}" \
--nproc-per-node="${NPROC_PER_NODE}" \
--node-rank="${NODE_RANK}" \
--master-addr="${MASTER_ADDR}" \
--master-port="${MASTER_PORT}" \
train.py \
--data-path=/mnt/datasets/train \
--checkpoint-dir=/mnt/checkpoints/experiment-001
运行前可以先检查端口和 GPU 是否满足预期:
# 两个节点都执行
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv
# 第二个节点执行,验证能否访问主节点 rendezvous 端口
nc -vz 10.0.0.10 29500
在生产环境中,可以将这些参数交给 Kubernetes Job、Kubeflow Training Operator 或其他训练编排系统管理。关键不是把命令“搬进 Pod”,而是确保编排系统能够同时处理以下状态:worker 数量、GPU 资源、主节点发现、端口连通性、失败重试和检查点恢复。
可观测性应回答“为什么慢”和“为什么失败”
训练平台至少应同时观察三类指标:
- 资源指标:GPU 利用率、显存、功耗、温度、CPU、内存和本地磁盘吞吐。
- 训练指标:step 时间、吞吐量、数据加载耗时、通信耗时、loss 和检查点时间。
- 平台指标:任务排队时间、Pod 启动时间、节点故障、镜像拉取时间、网络错误和重试次数。
特别要关注“GPU 利用率不低但训练仍然很慢”的情况。此时可能是通信等待、数据加载抖动或某个慢节点拖住了同步,而不是 GPU 算力不足。
日志也应带上实验 ID、任务 ID、节点名、rank 和镜像版本。否则多个 worker 的日志混在一起时,排查一次 collective timeout 会非常困难。
落地时的取舍与检查清单
不必一开始就追求完整的 AI 平台。可以按下面的顺序推进:
- 先用固定规模的多节点基准任务验证 GPU、网络和存储;
- 再建立统一的任务描述,明确 worker 数量、GPU 型号、数据版本和检查点位置;
- 为训练任务增加启动超时、失败重试和最大运行时长;
- 将 GPU 利用率、step 时间和数据读取时间接入监控;
- 用故障演练验证节点重启、网络中断和对象存储短暂不可用时的行为;
- 最后再根据队列规模引入成组调度、优先级、抢占和多租户配额。
可靠的云原生 AI 基础,不是某一个 GPU 插件或某一套训练框架,而是一条从资源发现到任务恢复的完整链路。平台团队真正要交付的,是让研究人员能够稳定地提交训练、理解训练速度,并在失败后以可控成本继续运行。