☰
AI基础设施实战:从GPU集群搭建到分布式训练工程化
2026/10/26 4:09:44 网站建设 项目流程

1. 聊一聊AI基础架构——先从一线视角出发

很多人一听到“AI基础架构”或“AI-Infra”,第一反应就是GPU服务器、Kubernetes集群、容器镜像这些重装备。确实,这两年AI的火热把底层基础设施的重要性推到了前所未有的位置,但真正在一线摸爬滚打过的人会告诉你:AI-Infra从来不是简单的“堆机器、装驱动、跑训练”这么一回事。它是一整套把算力、数据、模型、流程、监控串起来的系统工程,背后要解决的是“让算法工程师能高效地用上算力,让模型能稳定地训练和上线”这个核心命题。

我这些年一直在一线负责AI平台相关的工作,从最初几台裸机手工配环境,到后来管理几百卡规模的GPU集群,再到设计自助化的模型训练与推理平台,踩过的坑、走过的弯路,确实不少。这篇算是我对自己一线AI-Infra之路的第一章复盘,主要想聊聊最核心的东西:算力环境怎么从“能用”走向“好用”,分布式训练的工程化怎么做,以及一线工程师最常遇到的故障和排查思路。

如果你正准备进入AI基础设施这个方向,或已经在做相关平台建设但总觉得哪里别扭,这篇文章应该能给你一些真实的参考。我不打算写教科书式的方案,而是把我实际操作中的选型逻辑、失败教训、调试细节摊开来讲。你在别的文档里能看到的概念,我这里尽量讲“为什么”和“怎么落地”。

2. 算力环境建设——从裸金属到GPU集群

2.1 为什么一开始就该上容器化

先说说我自己的经历。早年间做AI训练,用的还是物理机方案:一台8卡GPU服务器,装好驱动、CUDA、Python环境、训练框架,然后算法同学直接SSH上去跑。听起来问题不大,但实际用起来全是痛点。

第一个痛点是环境冲突。今天A同学要TensorFlow 1.15配CUDA 10.0,明天B同学要PyTorch 2.0配CUDA 11.8,两个环境一撞,基本就要折腾半天。第二个痛点是资源利用率。物理机上跑任务,经常出现一个人占着整台机器,但GPU利用率只有20%的情况,别人想用也用不了。第三个痛点是复现问题。昨天调好的环境,今天手一抖升了个包,训练结果就不对了,查找原因非常痛苦。

后来我下决心迁移到容器化方案,核心思路是:用Docker镜像把CUDA、cuDNN、Python依赖、训练框架全部固化下来,再用Kubernetes做编排调度。这一步带来的好处是质的飞跃——环境彻底隔离了,镜像版本可追溯了,资源也能按需申请了。

我在这里的选型原则是:镜像体积适当控制,但不要走极端追求“最小镜像”。训练镜像里把常用的调试工具一起带上,比如vim、curl、lsof、htop,否则线上排查问题的时候你会发现连看日志都费劲。很多人一上来就用精简镜像,省了几个GB,到了排查问题时追悔莫及。

2.2 GPU调度与资源切分的几种方案

容器化之后,下一个核心问题是CPU、内存、GPU这些资源怎么分给每个训练任务。CPU和内存的分配在Kubernetes里用request和limit就能搞定,GPU则需要单独处理。

NVIDIA官方提供的device plugin是目前最主流的方案,它会把GPU当成一种可调度的资源暴露给Kubernetes。但由于NVIDIA GPU本身不支持原生显存隔离(不像CPU那样能通过cgroup硬性限制),所以通常的做法是整卡分配:一个任务申请1张卡、2张卡或8张卡,拿到的就是完整的物理GPU。

整卡分配的好处是稳定,坏处是碎片化严重。比如一个任务只要2GB显存,但只能占用一张完整的40GB卡,其他任务没法再用剩下的部分。对于数据并行这种训练方式来说其实还好,因为每个进程本来就需要一张完整的卡;但如果跑推理服务或小规模的调试任务,就很浪费了。

大小核、时间片、MIG(多实例GPU)、vGPU这类显存隔离技术我也都试过。时间片方案容易导致同一块GPU上的多个任务互相抢占,算力不稳定,不利于训练任务;MIG只支持部分较新型号的卡,而且切分之后不能动态调整,计划性要求很高。我自己在训练场景下还是倾向于整卡分配,然后在推理场景单独部署,避免两类任务混部互相干扰。

另外要说的是,在Kubernetes里配GPU,有几个细节容易翻车:

  • device plugin版本必须和驱动版本、容器运行时一致,否则会出现“发现了GPU但调度不上”的诡异问题。
  • 给Pod配置GPU资源时,不要把requests和limits设成不同值,否则调度行为会非常奇怪。
  • 如果混用不同型号的GPU卡(比如A100和L40S混在一批机器里),最好给Node打上标签,并用nodeAffinity或nodeSelector约束任务,避免模型在最不合适的卡上跑得奇慢无比。

2.3 镜像仓库与镜像管理规范

镜像这块,很多小团队一开始不太重视,随便搭一个Docker Registry就开干。等到团队规模大了、模型版本多了,才发现镜像管理有多重要。

我比较推荐用Harbor这一类企业级镜像仓库,主要原因是它支持镜像复制、漏洞扫描、RBAC权限管理,而且在多集群场景下,可以配置按需拉取。镜像命名规则也要提前定好,我见过很多团队镜像名随手写,比如“test”“final_v2”“new_test_3”,过了几个月自己都分不清哪个是哪个。

我这里建议的规范是:仓库名按项目区分,镜像标签必须包含语义化版本号或Git commit号,例如 ai-infra/llm-train:20240518-8f3a2c1 。这样任何一个镜像都能追溯到对应的代码版本,排查问题、回滚都方便很多。

还有一个容易被忽略的点:训练镜像里的基础层不要频繁变动。比如CUDA版本、Python版本这些底层系统组件,尽量保持稳定。不然每次重建镜像,所有上层依赖都要重新验证一遍,时间成本天差地别。正确的做法是分多阶段构建,把底层系统环境、算法依赖、业务代码分成不同层,业务代码频繁更新时,前面几层直接走缓存,构建速度会快很多。

3. 作业编排与全链路状态管理

3.1 为什么要从裸Pod走向模板化提交

容器化和调度搞定之后,下一步就是“作业要怎么提交”。最开始,我们是让算法同学直接写Kubernetes的YAML文件,然后kubectl apply上去。这个方案对熟练工还行,但普通算法工程师用起来抱怨很多:YAML太长太难写、环境变量太多记不住、每次都要复制粘贴改配置、跑完了想看看日志还得敲一堆命令。

后来我专门做了一个作业提交的前端界面和命令行工具,把创建训练任务的底层细节全部藏起来。用户只需要填几个关键参数:镜像地址、GPU卡数、训练命令、数据集路径。系统自动生成完整的工作负载配置,提交到集群里去。

这个设计的关键点是模板化,也就是把“如何运行一个训练任务”的公共部分沉淀成模板,把“每个任务不同的部分”暴露成参数。好处很明显:第一,普通用户不用理解底层细节,填个表单就能跑训练;第二,平台侧可以在模板里注入统一的日志收集、健康检查、指标上报逻辑,确保每个任务都有可观测性;第三,可以做资源配额控制和审批流程,避免某个用户一次性提交几百个任务,把集群资源全部打满。

3.2 日志、指标与训练进度的采集

任务能跑起来只是第一步,能“看得到”任务跑得好不好,才是平台价值所在。这一块我强烈建议在一开始就建设好,而不是等到出了问题再补。

日志采集用标准化的方案:stdout和文件日志通过Fluent Bit采集到Elasticsearch或Loki,再通过Grafana或Kibana统一查询。关键是每个训练任务要有唯一的ID,日志里要带上这个ID,否则多任务并发时没法按任务过滤。

指标采集这块,我做了两层:第一层是节点级和Pod级的监控,用Prometheus + node_exporter,看CPU、内存、GPU利用率、显存占用、GPU温度、PCIe带宽等;第二层是框架级的监控,比如PyTorch的loss曲线、学习率、吞吐量这些训练指标,通过自定义的Metrics接口输出到Prometheus。

说实话,GPU利用率监控是必须的,但不是唯一指标。有段时间我发现很多任务的GPU利用率很高,但训练速度并不快,后来才排查出来是数据加载环节卡顿,GPU在空转等待数据。所以训练类任务,我还会额外监控数据加载耗时、CPU侧的处理耗时,以及GPU计算耗时,只有这几项差距不大,才算健康。

3.3 资源配额与成本治理

平台一旦对外开放,资源配额就是必须立刻解决的问题。没有配额管理,总会有人一次提交大量任务或者把资源占着不用,影响整个团队的效率。

我用的是Kubernetes的ResourceQuota和LimitRange作为基础,再在上层做了一层项目维度的配额管理:每个项目组一个命名空间,配额(GPU卡数、CPU、内存、存储)由管理员统一分配。任务提交时,系统做预检查,配额不够就直接提示用户,而不是提交上去了再被调度器拒绝。

成本治理这块,没有一套完美的方案,关键是先做到“可归因”:每个任务用了多少GPU卡时,是哪个项目使用的,跑完了账单归到谁头上。我实现了按任务维度的计费数据采集,GPU卡时数按卡型和时长计算,存储按占用量和时间计算,最后汇总到项目维度做月度报表。有了这个数据之后,优化方向自然就出来了——比如有些项目其实不需要A100级别的卡,使用稍低规格的卡就能满足需求,成本能省一大截。

4. 分布式训练的经验与踩坑

4.1 分布式训练该怎么配置

模型大了单卡放不下,或者训练周期太长,就得上分布式训练。但分布式训练不是简单加几张卡就行的,这里面学问非常大。

一般常用的是数据并行,也就是每个GPU上放一份完整的模型副本,把训练数据拆成多份,每个GPU各自算梯度,再通过梯度同步把大家更新到同一个模型状态。PyTorch的DistributedDataParallel(DDP)是最常用的方案,配置起来也很方便,但有几个关键参数必须理解到位:

  • world size:参与的GPU总数,等于数据并行进程数。
  • rank:当前进程的编号,从0到world size-1。
  • master address和port:用于进程间通信的IP和端口。

我在实际配置中遇到的常见问题:

  • 没有设置环境变量或初始化参数,导致每个进程各自为政,loss波动很大,训练效果跟单卡没区别。
  • master地址写错,不同节点之间连不上,任务一直卡在等待同步。
  • batch size设置不当时,如果全局batch size变大而学习率没有相应调整,loss会出现发散现象。

4.2 数据并行之外的选择

当模型大到单卡甚至多卡都放不下的时候,就得考虑模型并行、流水线并行或张量并行。这几类方案有一个共同点:可以把一个模型切分到多张GPU上。

  • 流水线并行:把模型的不同层放在不同的GPU上,数据经过GPU1算完传到GPU2继续算,像流水线一样。缺点是存在“流水线气泡”,某些GPU在等待前一个阶段的输出,利用率会打折扣。
  • 张量并行:把某一层的权重矩阵切分到多张卡上,同时计算同一个层。通信量非常大,一般要求机器内部有高带宽(比如NVLink),跨机效果会差很多。
  • 混合并行:也就是3D并行,同时使用数据并行、流水线并行、张量并行。大语言模型预训练基本都用这个套路。

我自己选择并行策略时的参考逻辑是这样的:

模型规模单卡可用性推荐方案关键考虑
小于单卡显存可放普通训练,或数据并行加速优先保证数据加载速度,避免GPU空闲
单卡放不下部分卡可放流水线并行+数据并行注意切层平衡,避免某张卡成为瓶颈
单卡完全放不下所有卡都放不下张量并行+流水线并行+数据并行小心通信瓶颈,跨机张量并行要慎重

4.3 断点续训不是一件小事

大模型训练动辄几天甚至几周,期间任何一次故障都可能前功尽弃。所以断点续训(checkpoint保存与恢复)是训练工程里绝对绕不开的一环。

最朴素的方案是周期性保存模型权重,每隔N步写一份checkpoint文件。训练中断时,从最近一份checkpoint重新拉起。但这事做起来有几个坑:

第一,checkpoint保存不能只有模型权重,还要把优化器状态、学习率调度器状态、当前epoch和step、随机数生成器状态一起存住。否则恢复到一半,排名、学习率对不上,训练效果会跑偏。

第二,只保存模型权重的话,恢复时虽然loss能继续下降,但训练曲线会在中断处出现明显跳变,因为优化器内部的状态(像Adam的二阶动量)丢了。

第三,checkpoint一定要做异步保存,不能在训练主线程里同步写文件,否则每个保存周期都会出现一次训练停顿。存储够大的话,多保留几份历史版本,别只留“最新一份”,因为有可能最新那份本身已经损坏或meta信息不完整。

5. 故障排查实录与稳定性建设

5.1 两个我印象很深的故障

第一个是“GPU利用率忽高忽低,训练速度上不去”。现象是NVIDIA-smi显示GPU利用率在20%到95%之间剧烈波动,loss也在抖动。我排查了一圈,先排除了模型代码问题,然后把目光放到数据加载上。检查了数据读取的进程数、磁盘IO的负载和网络文件系统的延迟之后,发现是因为所有训练节点共享同一批数据挂载点,多任务一起跑时,磁盘IO被拉爆,数据读取等了好几十秒甚至几分钟。GPU排队等数据,自然就出现剧烈的利用率波动。解决方案是把数据集预热到本地SSD,同时增加了数据预取线程数,问题很快缓解。

第二个是“调度器认为资源充足,但任务一直Pending”。GPU设备插件发现了,节点状态也是Ready,可是任务迟迟调度不上去。后来排查发现是某些GPU卡的显存被一个残留进程占用了,导致Kubernetes认为该节点的可分配GPU数量减少了。解决方式并不复杂:把节点的GPU资源上报改为动态检测,并启动一个巡检脚本,定时清理异常残留的GPU进程。从那以后,这种“幽灵占用”问题基本没有再出现。

5.2 稳定性体系建设的优先级

经历过几次严重事故后,我对稳定性的理解从“出了问题快速恢复”转变成了“尽量避免出问题”。这里按优先级排序,是三个层面的事情:

第一个层面是冗余和容错。关键组件一定要多副本部署,比如Kubernetes的管控组件、镜像仓库、日志系统、监控系统,不能有单点。Kubernetes本身有高可用方案,但要真正落地,很多边边角角的地方都得检查到——etcd备份做了没有、镜像仓库磁盘空间够不够、监控系统本身的持久化配置是否可靠。

第二个层面是预案和演练。核心服务的故障预案要写下来,而且每过一段时间要真的演练一次。比如“镜像仓库挂了,该怎么紧急恢复?”,“某个训练节点网络失联,如何快速迁移任务?”这些问题,纸上谈兵没用,得实际推演一遍才知道漏洞在哪。

第三个层面是可观测性。日志、指标、链路追踪,这三件套齐不齐,决定了出问题时是“十分钟定位”还是“三小时盲猜”。我这里的经验是,不要等到需要了才去补,因为到时候你根本不知道需要什么。在一开始就把关键组件、关键路径的监控点规划好,像健康检查API、核心接口的延迟和错误率、资源队列的长度、作业失败率,这些都应该有对应的指标面板。

5.3 常见问题速查表

我把自己这些年最常遇到的问题整理成了一张速查表,供有类似经历的同行参考:

现象常见原因排查思路与处理方式
Pod一直Pending资源配额不足或节点GPU被占满描述Pod拿到调度事件,检查配额与节点资源,再判断是否有残留进程
训练任务启动后闪退镜像缺少依赖,或启动命令报错看Pod日志,先确认能不能本地拉起同样镜像做复现
多卡训练速度上不去网络通信瓶颈或数据加载过慢分别检查节点内NVLink带宽、跨节点TCP速度、数据读取耗时
GPU利用率高但吞吐低频繁同步或算子效率低用Profiler看耗时分布,找出热点算子和通信等待
保存Checkpoint时训练停顿写入方式阻塞了主线程改为异步保存,并把存储路径放在低速盘或独立卷上
集群重启后GPU调度异常驱动或device plugin状态不一致按顺序重启kubelet和device plugin,确认设备数量对应

6. 关于“第一章”之后的延伸思考

这算是我AI-Infra之路的第一阶段总结,主要围绕算力、调度、训练工程化这些最基础的能力展开。一路走来,很多当时觉得极其棘手的故障,回头看都是因为某个环节的基础没打好——镜像规范没定、监控指标没埋、资源配额没设——这些问题越早处理,后面的路就会越顺。

我做这一行最大的感受是:AI基础设施其实是“慢功夫”,没有银弹。你不会在搭建完某套系统之后就一劳永逸,因为上层模型在演进、算力规格在变化、团队规模在扩张,底层平台永远有新的问题等着你。但反过来看,只要你愿意把每一个细节吃透、把每一次故障当作升级的机会,这套系统会变得越来越皮实,你在团队里的价值也会越来越明显。

如果你也在建设AI基础设施,我的建议是先把基座打稳:统一的容器化环境、可靠的调度体系、完整的可观测性,这三点在任何规模下都不过时。先别急着追各种花哨的新概念,把这些基本功练扎实了,后面遇到模型规模变大、并发任务增多,你才有底气去接住。

第一章就先写到这里。接下来我大概率会继续把推理服务优化、训练成本治理、多集群管理这些话题陆续整理出来,毕竟AI-Infra的版图还很大,路才刚刚开始。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询