去年年底,我被调进了公司新成立的算力平台组,接手的第一件事就是盘点散落在各业务线的 GPU 服务器。在那之前,我对“AI-Infra”的理解基本停留在“会上显卡的人”这个层面。真正走进这个领域才发现,一线工程师眼里的 AI-Infra,既不是算法工程师挂在嘴边的训练框架优化,也不是领导汇报里的漂亮算力规模,而是每天跟 GPU 排队、显存碎片、通信超时、镜像拉取失败这些具体到不能再具体的问题打交道。
这篇博文想写的,就是我这半年多从零摸进 AI 基础设施领域的第一段经历。它不是什么高深的论文解读,而是一个业务后端工程师视角的“转行实录”:我踩了哪些坑、搞懂了几件重要的事、哪些认知被彻底刷新。如果你也正在经历类似转型,或者手头要开始维护 GPU 集群,希望这篇能帮你少走几步弯路。
1. 从业务线被调进算力平台组:第一周的认知冲击
1.1 接到通知时的三个灵魂拷问
我是做业务后端出身的,日常打交道的是接口耗时、数据库慢查询、缓存命中率这些。当部门调整的消息传到我这里,说要让我去算力平台组时,我脑子里蹦出来的第一个问题是:AI Infra 到底是干嘛的?第二个问题是:我一个连训练脚本都没写过的人,去那儿能做什么?第三个问题更直接:这个组会不会很快被裁掉?
后来证明,前两个问题一周内就有了答案,第三个问题在过去半年反复被大模型浪潮回答了无数次。这里先不聊趋势,只说落地层面:算力平台组在公司里的定位,就是把 GPU、存储、网络这些底层资源变成一种“可自助申请、可计量、可排队”的服务,交付给算法团队和模型训练团队使用。听起来有点像 IaaS,但它比虚拟机集群复杂得多,因为 GPU 不是普通 CPU,它涉及显存、驱动、通信拓扑、多卡协同这些非常敏感的特性。
第一周,我被安排了三件事:盘点机房 GPU 资产、看一遍现有调度器的告警日志、跟着资深同事给模型组答疑。这三件事做完,我大概明白自己未来要面对什么了。
1.2 第一张架构图:AI 基础设施到底管什么
为了让自己快速上手,我画了一张至今还在迭代的架构草图。从上到下大概是这样:
- 最上层是训练平台和推理平台,算法工程师在这里提交任务、看日志、盯指标。
- 中间层是作业调度与资源管理,负责把“要 8 张卡跑 3 天”这样的需求翻译成一组容器、一组环境变量、一组端口。
- 再往下是基础设施层,包括 Kubernetes 集群、GPU 驱动与设备插件、高性能网络(比如 RDMA 或高速以太网)、共享存储(训练数据的读写路径)。
- 最底层才是物理资源:机房里的 GPU 服务器、交换机、存储阵列。
这个分层最让我吃惊的地方在于:AI 基础设施的“技术含量”并不只在 GPU 本身,而在于把从上到下的所有环节串起来之后,还能在任务高峰期稳定运转。比如存储带宽不够,训练任务会卡在数据读取上;网络拓扑不对,多机训练可能比单机还慢;驱动版本不一致,同一个镜像在不同节点上表现天差地别。这些问题,没有一个是你光看 GPU 能看出来的。
第一周我还记住了一句老同事的话:“在 AI Infra 里,你解决的最多的不是‘能不能跑起来’,而是‘能不能一直稳定地跑得快’。”这句话后来反复被验证。
2. GPU 资源的第一课:从“插在机器上的一块卡”到“可以被排队领取的资源”
2.1 device plugin 与资源上报机制
我刚开始接触 GPU 调度时,最不适应的一点是:为什么训练任务申请 GPU 的方式那么像“抢座”,而不是像调用一个 API 一样优雅?
这里得先补一个背景。在 Kubernetes 这类容器调度系统里,默认的资源维度只有 CPU 和内存。想让调度器知道“某台机器上有 8 张 GPU、每张 80G 显存”,必须借助“设备插件”机制。简单说,GPU 厂商会提供一个 device plugin 组件,它运行在每台 GPU 节点上,主动向 kubelet 上报“我这台节点有多少个自定义资源”,资源名通常长成某厂商.com/gpu这种形式。
上报之后,调度器才能在做资源匹配时,把“请求 1 个 gpu 资源”的 Pod,调度到“剩余可用 gpu 资源大于等于 1”的节点上。这个机制本身不复杂,但它带来的直接影响是:所有 GPU 都变成了“声称的资源量”,至于真实性能、显存带宽、卡间通信能力,调度器完全不知道。这就像你订酒店时只知道自己订了几个房间,并不知道房间的窗户朝向、隔音效果、离电梯多远——这些信息在入住后才会真实影响体验。
2.2 共享、切分与排队背后的资源语义
GPU 粒度只是一个开始。真正让人头疼的是“怎么分”的问题。最常见的三种做法:
- 整卡独占:一个任务占一张卡,简单粗暴,隔离性好,但利用率往往不高。
- 显存切分:把一张卡的显存划成几份,让多个小任务共用,适合推理这种显存占用小、GPU 算力需求也小的场景。
- 时间片共享:多个任务轮流用同一张卡的算力,适合交互式开发、小规模实验,但存在性能干扰。
我印象很深的是一个实际案例:模型组同事抱怨“训练任务变慢了,是不是有人在抢资源”。查了半天发现,是另一个团队把一些低优先级的调参任务提交到了同一批节点上,时间片共享策略下,这些任务会周期性打断训练任务的 GPU 计算。
这背后其实是资源语义的两个矛盾:一是“资源总量够不够”,二是“资源分配后性能稳不稳定”。一个任务拿到 8 张卡,但这 8 张卡如果是被其他任务部分占用的,那实际算力可能只有 6 张卡的效能。把这些逻辑讲清楚,比单纯的容量规划难得多。
2.3 为什么排队策略决定了训练平台的“用户体验”
除了怎么分,还有“怎么等”。GPU 资源紧张时,任务会进入排队状态。排队策略如果太笨,会出现一个很尴尬的情况:后面提交的大任务,把前面所有人的小任务都堵住了;或者优先级高的任务可以无限插队,导致低优先级任务长时间饿死。
我接手的第一版调度器配置,排队的逻辑比较简单,基本是先到先得加上人工干预。结果就是每周都有人来问“我的任务为什么还不跑”,而且问的人越来越多。后来我们引入了优先级队列、配额组、抢占策略,才总算把“资源分配”这件事从“人工协调”变成了“规则说话”。
这段经历让我意识到,AI 基础设施里最难的从来不是某个单一技术,而是把调度策略、资源配额、用户预期三者对齐。算法工程师只关心“我什么时候能跑完”,平台工程师却要回答“在资源有限的前提下,怎么让所有人的任务都能在可接受的延迟内开始”。
3. 第一个从零排障的夜晚:训练任务为什么一直 Pending
3.1 从 Pod 状态反推调度链路
入职第三周,我经历了一次印象极其深刻的排障。当时一个模型团队的训练任务在平台上提交后,一直处于“等待调度”的状态,等了一个多小时都没起来。负责的算法同事来找我,语气里带着明显的着急:“是不是平台坏了?”
我当时还不太熟练,第一反应是去看集群节点状态:节点是不是 NotReady 了?内存是不是爆了?结果节点全都是 Ready,GPU 看起来也够。再仔细看,才发现问题出在“资源请求”与“节点可用资源”的匹配关系上。
这里科普一下排障的基本动作。当任务提交后,平台会创建一个对应的 Pod,调度器会尝试为它寻找合适的节点。如果一直找不到,Pod 的状态会停留在 Pending,并且调度器会写入一条事件,比如0/8 nodes are available: 8 Insufficient 某厂商.com/gpu。
这条事件告诉我们:不是资源不够,而是在“能满足要求的节点”上资源不够。于是下一步就去看任务请求了多少 GPU。结果发现,这个训练任务请求了 4 张 GPU,而集群里确实有 6 台节点各有 4 张空闲 GPU,按说不该失败。
3.2 第一层原因:显存请求被卡住了
继续往下查才发现,问题出在“显存请求”这个细节上。平台在封装训练任务时,为了让多任务能共享一张卡,会把显存作为一种独立资源上报。比如一张 80G 显存的卡,可以被切成 4 个 20G 的虚拟资源。这个任务请求的 GPU 数量虽然只要 4 张,但显存请求写的是“每张卡需要 40G”。如果某些节点虽然闲置 4 张卡,但每张卡的剩余显存碎片不足 40G,就会被调度器判定为不满足。
这种情况在训练任务密集、大家又都喜欢默认请求“整卡显存”的时候特别常见。解决办法有两个:要么把训练任务的显存请求调低一点,让调度器能做更精细的匹配;要么在平台层面增加“整卡调度”和“部分调度”两种模式,让用户显式声明自己是哪种需求。
我们最终改的是平台的任务模板,把所有训练任务的默认显存请求从“整卡 100%”改成“预留 80%,允许调度器在剩余 20% 上打包其他小任务”。这个改动本身不大,但对资源利用率的提升肉眼可见。
3.3 第二层原因:两个任务分到同一台物理机,谁也跑不快
资源匹配问题解决之后,任务确实起来了,但跑得极慢。训练 Loss 下降的速度,比我预想的慢了一倍。我们去看了 GPU 利用率监控,发现两张卡的使用率都只有 50% 上下。
一开始我以为是代码问题,后来看了一张“节点 GPU 卡间通信拓扑图”才明白:这两个训练任务虽然拿到了两张不同的 GPU,但恰好被调度到了同一台物理机上靠近同一 PCIe 交换机的两个插槽。如果是单卡任务,这完全没问题;但它们是两个需要频繁在 GPU 和 CPU 之间同步数据的任务,共享了 PCIe 带宽,互相拖慢了。
这个场景让我第一次意识到:GPU 调度不是简单的“数卡”,还得考虑“卡和卡之间的相对位置”。同机多卡通信和跨机通信的延迟差异,以及 PCIe 带宽争抢,都是真实存在的性能杀手。
3.4 排障链路复盘:一条命令一条命令追下去
这次排障前后用了一个晚上,对整个排查链路做个总结:
- 看 Pod 事件:确认是“找不到节点”还是“镜像拉取失败”还是“容器启动失败”。
- 看节点资源水位:确认是“总量不足”还是“单维度不足”。
- 看任务资源请求细节:确认 GPU 数量和显存请求是否匹配。
- 看调度后的实际表现:确认任务启动后 GPU 利用率、卡间通信是否正常。
- 看物理拓扑:确认多卡任务是否被分散到不同 PCIe 域。
这几步说起来简单,但没有真实踩过一遍,很难体会其中的微妙。尤其是“总量不足”和“匹配不上”这两种情况,从最终用户的视角看都是“卡住了”,但解法完全不同。
4. 以为自己会写分布式了,结果被集合通信教做人
4.1 多卡训练不只是“多开几个进程”
解决了调度问题,我开始接触到真正的多卡训练场景。这时候才发现,“分布式训练”这四个字远比我想象的复杂。
我们组维护了一个常用的多卡训练镜像,里面已经预置好了启动脚本。我刚开始以为,所谓多卡训练就是把同一个训练脚本复制 8 份,每份跑在不同的 GPU 上。后来仔细看脚本才发现,每个进程都有自己的“身份”:rank 编号、主节点地址、网络通信端口等。进程之间要用一种叫“集合通信”的机制来同步梯度。
打个比方,这就好比 8 个人一起解一道很重的数学题。每个人负责一部分题目,但每隔一段时间,大家必须停下来,把各自算出的中间结果互相交换一遍。这个交换过程如果设计得好,大家同步前进;如果设计得不好,其中一个人慢了,其他所有人都在等它。
这个“交换过程”在工程上对应的是集合通信库,最典型的是 AllReduce 操作:把每个 GPU 算出来的梯度汇总起来,再广播给所有 GPU。通信的效率和频次,直接决定了多卡训练的加速比。你以为 8 卡能快 8 倍,实际上通信开销会把加速比拉到 6 倍、4 倍,甚至负优化。
4.2 环境变量、慢节点与超时的蝴蝶效应
有一次,一个 32 卡的任务在一个小时内连续失败了好几次,报的都是同一个错误:通信超时。通信超时,翻译成人话就是:某个进程在等待其他进程时超过了预设的等待时间,整个训练任务被强制中断。
排查这个问题时,我们先看节点,发现参与训练的所有节点都是健康的。再看网络,带宽也没问题。最后拉着模型组一起看启动脚本,才发现问题出在一个特别隐蔽的地方:不同节点上的环境变量不一致。
多卡训练启动时,每个进程都有一些关键环境变量,比如“我是第几个进程”“总共有多少个进程”“通信端口是哪个”。如果某个节点上这些变量没有正确传入,进程就会不知所措,表现为迟迟不给主进程回应,最终触发超时。
这给我们敲了一个警钟:分布式训练的稳定性,藏在一个看似无关紧要的环境变量里。后来我们把所有环境变量的注入逻辑收口到平台侧,统一生成、统一注入,而不再依赖算法同学自己写的 shell 脚本,这个问题才彻底消失。
4.3 一个 10 小时到 7 小时的性能优化案例
除了稳定性,性能优化更是集合通信的重大课题。我参与的第一次性能优化,是一个图像类模型的训练任务。
最初的训练版本稳定跑完需要大约 10 小时。我们做的第一件事,是把训练过程中的“时间切片”打开,看每个 step 的时间构成。结果发现,真正花在 GPU 计算上的时间只占一半左右,另外一半花在了数据读取和预处理上。
问题出在数据管道:训练脚本用的是同步数据加载,每个 step 都要先等 CPU 把一批图片预处理完,再传给 GPU。优化方式也不复杂:把数据加载改成多进程预取,让 CPU 在 GPU 计算当前 batch 的同时,提前准备下一个 batch。改动之后,每个 step 的耗时下降了接近 30%,训练总时长从 10 小时降到了 7 小时左右。
后来又做了一轮通信优化:把梯度同步频率从“每个 step 都同步”改成“每两个 step 同步一次”,减少了通信次数,又缩短了一点时间。这两步做完,我最大的体会是:性能优化不是上来就看 GPU 利用率,而是要先看“时间都去哪了”。
5. 第一章收尾:写给同样半路出家的 AI-Infra 工程师的避坑清单
5.1 我踩过又爬出来的坑,汇总成五句话
走到这里,我的 AI-Infra 第一段旅程也算告一段落。如果让我把这半年的经验浓缩成五句话,我会这样写:
- 先把资源模型弄清楚,再碰调度器。GPU 数量、显存、通信拓扑是三个独立维度,不能混在一起谈。
- 一个任务“跑起来”和“跑得快”是两码事。前者看调度,后者看通信、数据管道、驱动稳定性。
- 一切稳定性问题,先看日志和事件,再猜原因。Pod 事件、节点事件、训练进程日志,每一层都能告诉你一部分真相。
- 和算法同学沟通,要使用“效果语言”而不是“机制语言”。说“你这个任务的显存请求不合理”远不如说“把显存请求调低 20%,排队时间预计能缩短一半”来得有效。
- 资源利用率高的集群,不等于稳定的集群。为了利用率牺牲太多稳定性,最终会让所有人的任务都变慢。
5.2 这个岗位最容易被低估的能力:读日志和数数
如果让我重新回忆这几个月的成长路径,我会说,AI-Infra 工程师最重要的能力不是会写多复杂的代码,而是会把“模糊现象”转化成“具体数字”。
比如“我的任务很慢”,到底慢在哪?是排队时间慢,还是容器启动慢,还是训练过程慢?每一种慢对应的时间和数值都不一样。再比如“集群快满了”,到底是 GPU 满还是显存满还是存储带宽满?这三个“满”的应对策略完全不同。
所以,我给自己的要求是,每次汇报问题都必须带着数字去,不带数字的问题不叫问题,叫感觉。养成这个习惯之后,不管是和领导沟通还是和算法协作,效率都高了很多。
5.3 下一章的预告:从“能跑”到“跑得便宜”
第一章我基本完成了“让训练任务稳定跑起来”这件事,但我知道这只是一个起点。接下来要面对的,可能是更硬的骨头:资源成本核算、多集群调度、GPU 利用率持续优化、训练任务自动扩缩容,以及更复杂的大规模多机训练场景。
这些内容如果后续有时间,我会继续写成第二章、第三章,每一篇都基于实际踩过的坑来写。
最后再分享一个小习惯
半年多来,我养成了一个很小的习惯:每次排完一个棘手的故障,都会在文档里记三样东西——问题现象、排查链路、根因。不写长文,只写要点,但一定要写“当时哪个信息是转折点”。这个习惯帮我节省了大量重复排查的时间,也让我在处理新的奇怪问题时,能更快地定位方向。
如果你也是半路出家做 AI 基础设施,建议你也试试这个办法。很多东西看似没有规律,但把所有踩过的坑串起来以后,你会发现自己的直觉会变得异常准。