ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI-Infra一线实战:从零搭建训练集群的踩坑指南

AI-Infra一线实战:从零搭建训练集群的踩坑指南

我做了六年的AI基础设施,从最初一个人给算法团队搬机器、装驱动,到后来带一个小团队维护上千卡规模的训练集群,中间踩过的坑比写过的代码还多。这个系列我想换个方式,不讲那种PPT上的宏大架构图,就讲一线工程师在AI-Infra这条路上真实会遇到的问题、真实会做的取舍、以及很多文档里根本不会写的细节。先把话放这儿:AI-Infra不是什么玄学,它就是把“让模型能更快更稳地跑起来”这件事做到极致。第一章先聊聊我眼里AI-Infra到底是个什么东西,以及我们从零搭一个训练环境时,最先要面对的那些基础但极其关键的问题。

1. 先把一线工程师眼里的AI-Infra讲清楚

1.1 我的定义:不是K8s,也不是运维

很多人一听到基础设施,第一反应是Kubernetes,第二反应是运维。这不能算错,但至少不完整。我自己的定义是:AI-Infra是位于“裸机硬件”和“模型训练/推理”之间的那一整层,它的职责是让算法工程师能够持续、高效、可控地使用算力。这句话拆开有三层意思:持续,意味着集群不能三天两头崩溃;高效,意味着算力利用率不能惨不忍睹;可控,意味着谁用了多少卡、跑了什么任务、花了多少钱,都得清清楚楚。

这层东西具体包含什么?往下拆就是五个子模块:计算资源(GPU/NPU等加速卡)、网络(节点间通信)、存储(数据集和检查点)、调度(任务怎么排队、怎么抢资源)、可观测性(出了问题怎么定位)。很多人只盯着第一项,觉得买够显卡就完事了,结果任务一跑分布式就发现网络是瓶颈,数据集IO卡住的时候GPU利用率掉到个位数,检查点写到一半写不进去直接白跑几十个小时。这种教训我见过太多次了。

之所以说AI-Infra不是单纯的运维,是因为运维通常是“保证系统别出事”,而AI-Infra在不出事之外还要回答一个更尖锐的问题:同样的硬件,你比别人多跑出了多少有效算力?后者是直接和成本、效率挂钩的,它要求Infra工程师能理解训练框架的通信模式、能看懂性能profiling数据、能手算带宽和吞吐量,这已经远超传统运维的范畴了。

1.2 这个系列适合谁,以及为什么从“训练侧”切入

写这个系列前我琢磨过读者画像。如果你是刚转行做AI基础设施的工程师,或者在一个小团队里既当算法又当运维,又或者在大公司刚接手一个训练平台项目,那么这个系列的匹配度很高。里面讲的问题不是从教科书里摘出来的,而是我在真实集群上处理过的。如果你已经是资深从业者,那很多内容可能你比我更熟,权当互相印证,也欢迎指正。

为什么第一章先切训练侧?两个原因。其一,训练是算力消耗的大头,也是出问题最多的地方;推理虽然对延迟敏感,但单个问题域相对收敛,更适合放到后面章节单独聊。其二,训练侧的基础设施逻辑恰好能把计算、网络、存储、调度这四个核心要素全部覆盖到,讲完训练,你对整条链路的理解就成型了。现实中的算法同学工作流基本就是:写代码、准备数据、申请资源、跑训练、调参数、再跑,而Infra的使命,就是让这个循环里每一步都不卡壳。

另外说明一下,这个系列里的实操基于我自己维护过的Linux环境,GPU和国产加速卡我都用过,Kubernetes和Slurm也都接触过。不同硬件、不同调度器的细节有差异,但底层的排查思路和设计原则是通用的,我尽量在讲具体方案的同时讲清楚背后的判断逻辑,你拿到自己的环境里也能迁移着用。

2. 一个小型训练集群的从零搭建实录

2.1 硬件选型:算力卡之外,内存与存储才是隐形瓶颈

2019年前后,我所在的团队第一次自建训练集群,当时大家讨论的全是买什么加速卡,CPU和内存配置基本上是随手选的,存储更是清一色买了普通的SATA盘挂在服务器上。结果第一个多机训练任务跑起来,问题全暴露了:单卡数据加载慢,CPU解压数据跟不上,日志一多磁盘直接打满,教训非常深刻。

先说内存。很多人忽略了训练任务里的CPU开销不只是数据加载,还有数据增强、预处理、tokenizer等逻辑。如果一张卡要搭配的CPU核数或内存不够,GPU每轮迭代都得空转等数据,整体吞吐断崖式下跌。我后来总结的经验是,单张卡附近至少保证8到16个物理线程和64GB内存,具体比例看你跑什么任务——如果是离线训练、数据预处理量大的场景,内存最好再往上加。这个配置看起来奢侈,但对比GPU空转造成的资源浪费,这点钱是最划算的投资。

再说存储,这是新手最容易踩的大坑。本地盘的容量和IO能力都有限,多机共享数据集必须上并行存储。我们看到过太多场景:数据集放在某个节点的本地盘里,然后别的机器通过NFS来拉,训练刚开始就卡在大量小文件的读取上。后来换成了并行文件系统,但随之而来的又是带宽分配的问题——几十个节点同时读同一个数据集,跑得慢的任务会无限拖快任务的进度。这里我建议小型集群直接考虑对象存储加缓存层的方案,数据集放对象存储,训练节点配NVMe缓存盘或者用分布式缓存加速,既便宜又够用。我和朋友们聊过,这个方案在20卡以下的小集群里几乎是性价比最优解,维护成本还低。

2.2 容器与调度:为什么不能“裸跑”

早期团队为了省事,直接在物理机上装驱动、配CUDA、跑训练进程,结果就是每次换框架版本都像经历一次“环境炼狱”。不同项目用的PyTorch版本不一样,有的要CUDA 11.8,有的要12.1,装A版本会把B版本的库给覆盖掉,互相折磨。

我的建议非常简单粗暴:从第一天起就上容器。容器把CUDA驱动、运行时库、Python依赖全部隔离进镜像里,算法同学拿到一个镜像就能在任何一台机器上复现环境。这里需要注意一个关键细节:容器内的CUDA版本要和宿主机驱动版本匹配。你可以把驱动理解成操作系统的一部分,容器内的CUDA工具包是应用的一部分,应用侧版本新一点、驱动老一点通常会兼容,反之就会报错,表现往往是“CUDA driver version is insufficient”。所以,宿主机驱动要尽量保持较新版本,给容器内工具包留足空间。

调度层面,我的观点是中小集群不必纠结Kubernetes和Slurm哪个更高级,关键看你团队的画像。偏算法研究、需要交互式调试的,用Kubernetes加GPU调度插件更顺手,算法同学可以像提交一个服务一样提交训练任务,也能方便地暴露端口看监控。偏传统科学计算、大量并行批处理任务的,Slurm的作业队列模型更直观。我们最终选了Kubernetes路线,配套GPU插件实现显存和卡数的资源声明,算法同学在YAML里写nvidia.com/gpu: 8就能拿到8张卡,不需要碰任何底层细节。要说稳定性和生态成熟度,两者都够用,选哪个主要看谁在用、用起来顺不顺手。

2.3 网络与存储:最容易绕远路的地方

很多刚接触分布式训练的人会忽略网络,以为只要交换机端口速率高就行,实际不是这样的。多机训练时,显卡之间要频繁同步梯度,通信模式非常密集。比如PyTorch的分布式数据并行(DDP)在每次反向传播结束之后,都要做一次全规约(AllReduce),把所有节点上算出来的梯度加到一起。如果节点间带宽不够或延迟过高,整个集群的算力会被通信拖死。

业内常见的做法是用InfiniBand或者RoCE这类RDMA网络,它们能绕过操作系统内核协议栈直接在网络接口之间传数据,延迟和CPU开销都低很多。但不是说没有RDMA就不能跑分布式训练——我们在千兆以太网上也跑过百亿参数模型的训练,只是训练效率很难看,GPU利用率经常只有百分之三四十,大部分时间都耗在等待通信上。这里给个直观参照:如果你跑的是通信密集型的大模型训练,节点间带宽至少要到25Gbps起步,建议100Gbps;如果只是小规模单卡或数据并行任务,普通10Gbps以太网也能凑合,但千万别把集群设计成所有节点共享一个上行口,那样一旦并发任务多了直接拥塞。

存储的坑前面提了一些,这里再深入一层:检查点的读写。大模型训练动不动就存几十GB甚至上百GB的模型权重和优化器状态,每隔一段时间就要写一次检查点,如果存储的写入带宽不够,训练进程会阻塞在存盘这一步。我见过一次真实事故:检查点文件写到NFS上,由于NFS服务端性能不足,IO卡住,训练进程直接超时崩溃,几个小时后才发现,之前训练的几十个小时全白干了。这个事故直接推动了我在团队里立下一个规矩:训练工作目录一定放在高性能存储上,检查点可以异步写,但绝不能放在慢速NFS上阻塞主进程。

3. 训练任务跑起来以后,真正该盯什么

3.1 利用率不等于效率:先分清这几个指标

集群搭好、容器环境就绪、训练任务能跑,这算万事大吉了吗?远没有。我见过大量团队,任务确实在跑,但GPU利用率只有40%上下,大家还觉得“机器在干活呢”,殊不知有一大半算力在空转。要看清真实效率,关键要盯的不是简单的利用率百分比,而是一整套指标。

第一是GPU利用率,包括算力利用率和显存利用率。算力利用率反映核心计算单元被占用的程度,显存利用率看显存容量使用了多少。这两个指标单独看都不够,因为一个任务很可能算力利用率高、显存占用低(比如小batch的小模型),也可能反过来。第二是MFU(Model FLOPs Utilization,模型算力利用率),它衡量的是实际算力输出占理论峰值的比例。大模型训练里MFU做到50%以上就算不错了,如果只有百分之二三十,多半是数据加载、通信或框架本身有瓶颈。第三是吞吐量,比如每秒处理多少样本,这个指标最直接,但容易受batch size影响,不能跨环境横向比。

那我一般怎么监控呢?基础设施层面用Prometheus采集GPU指标、网络流量、存储延迟,Grafana做看板;框架层面的信息会配合训练日志里打印出来的loss、吞吐量,再接入类似权重监控平台的工具做训练过程的曲线追踪。有一次我们排查训练变慢的根因,就是从监控上看到某台机器的GPU利用率骤降到10%,其他节点正常,顺着网络监控一张图排查,发现是交换机的某个端口错误包暴涨,最后定位到光模块老化,换掉以后利用率立刻恢复。如果没有这套监控体系,这种问题排查起来像大海捞针。

3.2 分布式训练最常见的三个坑:邻居效应、慢节点、通信叠加

在多机训练环境里,有些坑是几乎每个团队都会踩的,我说三个最有代表性的。

第一个是“邻居效应”。同一个GPU上跑多个容器,彼此抢显存、抢算力、抢内存带宽,互相拖垮。这个问题在共享GPU出现后尤其严重,因为两张卡的物理资源可能不在同一个NUMA节点上,跨节点访问内存的性能损失非常明显。我们的解决办法简单但有效:一个物理GPU尽量只绑一个容器,或者用完整显存隔离加算力限制,必要时宁可让某个任务排队,也别几个任务共享一张卡去互相折磨。

第二个是“慢节点”。分布式训练中所有节点是同步推进的,每次迭代都要等最慢的那个节点完成通信和计算,一个节点慢了,整个集群都跟着慢。这就是“木桶效应”,跑得最慢的那个节点决定了全集群的速度。导致慢节点的原因可能是光模块老化、散热不良导致的降频、本地磁盘IO抖动,甚至其他业务在宿主机上抢占资源。定位办法比较直接:看每个节点的step耗时曲线,谁明显偏高就去查它的硬件状态。

第三个是“通信叠加”。当多个训练任务同时跑在同一个网络上时,AllReduce的流量会互相挤占带宽,造成任务间相互干扰。尤其在没有做网络隔离的小集群里,一个通信密集型任务能拖垮所有并发任务的速度。解决思路有两条:一是为高优先级任务做网络带宽保障;二是错峰调度,避免所有通信密集型任务扎堆同一时间跑。大厂里用的“网络染色”方案在小集群里不现实,毕竟不可能为每个租户买一套物理网络,但至少用流量控制限制住并发任务的总带宽,能避免最坏情况。

3.3 一套可复现的排障流程

排障是Infra工程师的家常便饭,我梳理了一个自己常用的排查顺序,写出来给你做个参照。

首先是确认现象。训练变慢、报错、卡住,先记录下时间点、影响范围、涉及的任务编号,最好把日志快照存下来。这一步看着简单,但很多人上来就翻日志,翻完才发现自己连什么时候开始出问题的都不知道。

其次是看监控。GPU利用率、显存、网络吞吐、存储延迟四类指标先扫一遍,很多时候瓶颈立刻浮现。比如GPU利用率低但网络吞吐高,明显是通信瓶颈;GPU利用率低但CPU利用率高,大概率是数据加载或预处理被卡住。

第三是缩小范围。确定是所有节点都慢还是个别节点慢,是所有任务都受影响还是特定任务受影响。方法就是在监控面板上按节点、按任务做维度拆分,几秒就能看出异常点。

第四是查日志和事件。看训练框架的日志、系统日志、调度器事件,重点找“timeout”“OOM”“NCCL error”“connection reset”这类关键词。这个阶段可以用一条命令快速抓取集群里所有节点的关键日志,然后统一分析,别一台一台登上去看。

第五是复现或回滚。如果是环境变更引起的问题,最快的方法是回滚最近的变更。如果是偶发问题,试着重建任务复现,复现时开详细日志,抓现场证据。

这套流程的核心逻辑是从大到小、从现象到根因,每一步都在做排除法,比漫无目的地猜要高效得多。我把它做成了一个checklist文档放在团队内部,新人排障直接照着走,效率提升明显。

4. 从救火队到产品团队:AI-Infra的一线生存法则

4.1 自助服务平台是硬门槛

如果Infra团队只是被动响应需求,那永远在救火,没有尽头。算法同学提交一个任务要找你开通权限、要环境、要配目录,每个请求都是打断,日积月累就把团队的时间消耗殆尽。这里没有捷径,必须做自助化,哪怕是一个简陋的门户也好。

第一件事是统一镜像管理。所有基础镜像、框架镜像放进镜像仓库,算法同学按需拉取,版本分明。这个投入不大,但直接消灭了“为什么我这台机器上跑不起来”这类高频问题。

第二件事是提供模板化任务提交入口。在Kubernetes里封装好训练任务的CRD,把“提交一个分布式训练”变成一个简单的配置文件甚至一条命令,算法同学不需要理解底层调度逻辑。

第三件事是数据集的统一挂载。把数据集做成一个抽象目录,哪个任务挂哪个数据集用标签声明就好,不用写死路径,也不用手工拷贝。

这三件事做完,Infra团队从“什么都管”变成“把边界管好”,剩余精力才能用来做性能优化、预算分析和容量规划。我见过很多小团队因为舍不得早期投入做这些东西,结果半年后每周都要花十几个小时处理重复的告警和请求,算下来反而亏得更多。

4.2 配额与优先级:资源编排背后的博弈

算力资源是稀缺的,尤其是小团队,几十张卡几十个人分,谁先谁后本身就是个博弈问题。我见过最原始的方案是“谁嗓门大谁先跑”——线下拉个群报备,谁先占住算力谁就能一直占着,效率极低且矛盾不断。后来我们引入了配额加优先级机制。

配额解决的是“每个人最多能用多少”的问题,按团队或者项目维度分配,防止某些任务吃光所有资源。优先级解决的是“资源不够时先给谁”的问题,按任务类型划分:正式训练任务高于调试任务,线上紧急任务高于离线实验任务。调度器会自动把低优先级任务抢占后调度到空闲资源上,或者挂起等待。

这套机制看起来简单,但要落地好有几个细节。一是要允许临时借调额度,否则突发任务来了会卡死在配额上;二是要有清晰的资源水位展示,让大家看到集群真实利用率,减少“明明有空位却不知道”的误解;三是调度的优先级策略要透明,否则算法同学会觉得系统不公。我们把配额申请流程做成了自助申请加审批,审批标准基本自动化,人为介入很少,后面争吵就少了很多。

4.3 Infra工程师的预算账本

最后聊一个很多人不爱提但特别现实的话题:Infra团队的价值怎么被看见。在大部分公司里,Infra不直接产生业务收入,它的价值容易被低估。我自己的体会是,Infra工程师必须学会用财务语言讲技术故事。

什么意思呢?比如你优化了任务调度,把集群利用率从40%提到70%,省下的算力是实打实的钱。你可以把这个折算成节省了多少卡时,再乘上单卡成本,得出一年的节省金额。又比如你做了自助化平台,减少了算法同学等待时长,这个换算成研发人力的释放,也是一笔账。再比如你建立了监控体系,把一次大事故的MTTR从五小时缩短到半小时,避免的损失也是可以估算的。

把这些数据定期整理成报告,向业务方和财务讲清楚:Infra不是成本中心,而是效率杠杆。这样做的好处很直接——第二年申请预算、扩容机器的时候,没有人会质疑你的投入。这不只是向上汇报的话术,它反过来也逼着Infra团队去用商业思维审视自己的每一个技术决策:这个方案贵不贵,值不值,能不能用更简单的方式达到同样的效果。

第一章差不多就写到这里吧。我在这一章里分享的都是最基础但最容易被忽视的东西:从AI-Infra的定义讲起,再到集群搭建时硬件、容器、网络、存储的选择依据,然后是训练任务跑起来以后真正该关注哪些指标、怎么系统性排查问题,最后聊了聊Infra团队怎么从救火队变成产品型团队。整个过程里没有特别高深的技术,更多的是在一线摸爬滚打中沉淀下来的判断力和优先级感。第二章我计划重点写一个具体的案例:一次多机大模型训练从动工到稳定跑满1500张卡的全过程,包括中途那次差点让人崩溃的网络故障怎么定位,以及为适配新的国产加速卡做算子适配时踩过的坑。要是你有类似的经历,也欢迎留言交流,大家互相补充信息差。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进