1. 先搞清楚AI-Infra到底是个啥
1.1 从一次"模型跑不起来"说起
我最早接触AI-Infra这个概念,不是在什么战略会议上,而是一次特别狼狈的线上事故。
当时我们有个团队训练一个十多亿参数规模的模型,早上十点提交任务,到下午三点还在排队。排队也就算了,真正跑起来之后,GPU利用率只有可怜的30%多。我过去一看,数据加载的瓶颈卡在CPU端,GPU每算完一个batch就要干等几百毫秒。那天我调了数据加载的prefetch参数、把TFRecord换成了更轻量的格式,又临时加了两台CPU节点做数据预处理,总算把利用率拉到了80%以上。但那种"靠人肉救火"的感觉,实在让人后怕——如果当时多几个团队同时抢GPU,系统早就瘫了。
后来我才慢慢理解,当时缺的其实不是某个参数,而是一整套叫AI-Infra的东西。
AI-Infra,全称AI Infrastructure,翻译过来是AI基础设施。它不是一个具体软件,也不是某一台服务器,而是围绕"模型开发、训练、部署、运维"全生命周期,把算力、存储、网络、调度、监控这些底层能力打包成一套可靠服务体系。打个比方,做AI模型像做饭,模型算法是菜谱,AI-Infra就是厨房里的水电气、锅碗瓢盆和排烟系统。你菜谱再牛,厨房一开火就跳闸,菜照样端不上桌。
1.2 AI-Infra的核心组件与职责边界
刚入门的朋友容易把AI-Infra理解成"装个GPU驱动就行",这真是大错特错。按我自己的经验,一套能扛住生产环境的AI-Infra,至少要覆盖下面这几个层面。
第一层是硬件资源层。GPU、CPU、高速存储、RDMA网络,这是底座。这里要解决的是"硬件怎么被上层软件优雅地使用",比如GPU驱动与CUDA版本兼容、显存管理、多机通信的拓扑感知。
第二层是资源管理与调度层。这是AI-Infra的"大脑"。多团队共享集群时,谁的任务优先跑?遇到资源碎片怎么处理?任务排队排到一半节点故障了怎么办?Kubernetes加上GPU调度插件(比如NVIDIA的设备插件和调度扩展)通常是这一层的主角,我需要根据场景和成本去选型。
第三层是训练与推理工程层。数据清洗流水线、模型训练框架的分布式配置、超参调优、模型压缩、推理引擎选型(比如vLLM、TensorRT-LLM)都在这一层。很多算法工程师觉得Infra工程师只管机器,其实不对,这一层是算法和底层资源之间的"翻译官"。
第四层是可观测性与运维层。监控告警、日志采集、链路追踪、成本账单。没有这一层,前面再好的基础设施也像没有仪表盘的飞机——飞得起来,但不知道什么时候会炸。
这四个层面不是各自独立的,而是像一条流水线。模型要训练,先经过资源调度分配GPU,再由工程层把数据和代码送上去,期间所有状态都要被可观测系统记录。任一层出问题,整个链路都会卡住。
1.3 为什么"一线工程师"视角特别重要
市面上写AI-Infra的书和课程不少,但大多数站在架构师或CTO视角,讲得特别宏大——什么万卡集群、大规模算力调度平台,动辄几百页PPT。但真正在一线处理过问题的人都知道,实际工作里90%的精力消耗在那些"书上不会写"的破事上:
比如CUDA版本和PyTorch版本不兼容导致训练任务莫名崩溃、GPU显存泄露但nvidia-smi看到的是正常状态、多机训练时网卡跑不满但带宽监控又看不出异常、集群里一票任务在用默认参数疯狂抢占带宽和磁盘IO……这些才是AI-Infra工程师的日常。
所以这个系列文章,我不想写那种"顶层设计"的正确废话。我想从一个在一线摸爬滚打的工程师角度,聊一聊实际落地时怎么选型、怎么排障、怎么优化,以及每一个选择背后的代价和取舍。第一章先打基础,把帮助你从零搭建一套够用的AI基础设施的关键环节讲透。
2. GPU资源管理:算力调度是AI-Infra的第一道坎
2.1 先学会看懂GPU的真实使用状态
在谈调度之前,先聊一个基础技能:看懂GPU的真实使用状态。
我经常看到同事跑过来问"我的GPU利用率怎么才5%",然后一脸懵。问题在于,很多人只看nvidia-smi的Volatile GPU-Util这一列。这个指标的含义是"采样周期内GPU忙碌时间的百分比",但它并不能完整反映真实利用率。
举个例子:一个GPU显存占用90%,GPU-Util显示98%,看起来一切正常。但我用nvidia-smi dmon -c 1再看细粒度指标,发现SM(流式多处理器)的活动频率很低,而显存带宽利用率(Memory Read/Write throughput)也不高。这说明任务虽然在"算",但计算强度很低,可能卡在数据搬运上,GPU的大部分算力单元其实在空转。
还有一个更隐蔽的坑:很多训练任务在数据加载阶段,GPU会周期性进入"空闲-忙碌-空闲"的锯齿状状态。你只看GPU-Util的平均值会觉得还行,但如果用nvidia-smi --query-gpu=utilization.gpu --format=csv -l 1采样观察,会发现GPU每隔几秒就掉到0%。这种周期性的饥饿状态,比持续的低利用率更影响训练速度,而且不容易被普通监控发现。
2.2 GPU资源池化和共享的落地姿势
有了看懂状态的基础,再来谈资源池化和共享。
一提到资源共享,很多团队第一反应是上Kubernetes。但我想多说一句:如果一个团队只有十几块GPU,机型和型号还不一致,上K8s的收益可能并不高。比如NVIDIA T4和A100混在一起,调度器很难以统一方式分配,还要额外维护一整套K8s组件,反而加重了小团队的运维负担。这种情况下,直接用虚拟化方案或者简单的排队脚本可能更务实。
如果规模到了几百卡以上,或者有多个团队共用集群,K8s就是主流选择了。NVIDIA官方提供了GPU设备插件(device plugin),安装后K8s就能识别GPU资源并调度容器。你需要在部署时提前设置节点标签(比如gpu-type=a100),因为不同任务的算力要求差异巨大——一个做模型微调的团队用T4可能就够了,一个训练7B以上大模型的团队则非要A100不可。如果不打标签,调度器把大模型任务分到T4上,任务大概率跑不起来或者慢到让你怀疑人生。
共享策略上也值得花心思。NVIDIA vGPU和MIG(多实例GPU)都能把一个物理GPU切成多个逻辑GPU。比如A100 80G可以切成7个MIG实例,每个约10G显存,适合推理场景。这里有个经验:MIG适合部署多个小模型推理,不太适合训练,因为训练时张量并行要跨MIG通信,性能损耗很大。像vLLM这种推理引擎也可以直接通过显存配置和并发参数实现单卡多服务共享,不一定非要上虚拟化。我的建议是:推理场景优先考虑模型层的并发和显存复用,真到切分场景再说MIG。
2.3 任务排队与优先级策略:别让调度变成玄学
GPU资源池化之后,下一个头疼的是任务排队和优先级。
我见过太多团队,一开始没有排队机制,谁先提交谁占资源,后来发现有个团队一口气提交几百个任务,把集群占满了,其他团队全都堵住。更惨的是,有些任务跑了两个多小时才发现参数错误,白白浪费算力。
引入优先级队列是必须做的。简单做法有三个原则:
第一,按业务等级分队列。核心在线业务(比如智能客服的模型推理)优先级最高,模型训练其次,实验性探索和离线数据处理最低。用K8s的PriorityClass就能实现,把高优先级任务的priorityClassName配高,低优先级任务就能在资源紧张时被抢占或挤到等待队列。
第二,设置每个团队或每个用户的最大资源配额。这个可以用K8s的ResourceQuota或者LimitRange来控制。别嫌麻烦,这一步能避免"一尸队把集群吃干抹净"的问题。
第三,做排队时间的可视化反馈。给算法团队一个入口,能看到自己的任务排在哪个位置,大概还要等多久。大部分人对"等待"的焦虑,其实是对"不确定"的焦虑。看到排队时间后,他们就不会反复来问"我的任务还要多久"了。
踩过的一个小坑是:K8s默认调度器在分配GPU时,可能会把两个任务的GPU分配到不同的物理机上,导致本来可以用NVLink加速的多卡训练退化成走PCIe甚至网络通信。解决方法是给调度器加拓扑感知约束,让同一个任务的多卡尽量落在同一台节点或者同一台交换机下。NVIDIA官方提供了拓扑感知调度扩展,值得研究。
3. 训练与推理的工程化落地细节
3.1 把训练任务跑稳:从环境一致性到底层调优
资源调度解决的是"能不能跑"的问题,训练工程化解决的是"跑得稳、跑得快、不出幺蛾子"的问题。这一节里我想聊几个容易在真实训练任务里拖后腿的点。
最优先要处理的是环境一致性问题。每个团队人员流动快,算法同学今天用这个版本的PyTorch,明天升级到那个版本的CUDA,一旦训练仓库里的环境依赖没有锁定,复现一个结果就变成噩梦。我用的是容器镜像加锁定版本号的方式:用一个Base Dockerfile锁定Python版本、CUDA版本、cuDNN版本、PyTorch版本,然后基于基础镜像构建训练镜像,每次改动都打上新的tag。核心原则很简单——模型代码可以迭代,但训练环境不能随意漂移。
其次是数据加载的优化。很多训练任务慢,不在GPU算得慢,而在数据喂得慢。我之前那个案例就是典型。优化方向有三个:一是用tf.data或者PyTorch的DataLoader时,要把num_workers调到合适值(通常和CPU核数正相关,但每个worker都会复制一份数据loader状态,开太多反而造成CPU和内存压力);二是用内存映射或者直接预取到内存,避免每个step都走磁盘IO;三是把预处理和数据增强放到GPU上跑(比如用NVIDIA DALI),把数据管线和计算管线重叠起来。
第三个容易忽视的是分布式训练的通信配置。多机训练时,PyTorch DDP默认走NCCL,NCCL的通信效率跟网络拓扑关系很大。如果机器之间是普通以太网,NCCL可能自动降级算法,性能惨不忍睹。建议启动训练前先用nccl-tests里的all_reduce性能测试工具跑一遍,确认实际带宽和期望值差距。如果用了RoCE或InfiniBand,还需要设好NCCL_IB_DISABLE=0、NCCL_IB_HCA之类的环境变量,否则NCCL根本不会走RDMA通道。
3.2 推理服务的高效部署:延迟、吞吐和成本的三方博弈
训练只是前半段,模型要产生价值还得部署成在线推理服务。推理优化里最核心的矛盾,是延迟、吞吐和成本三者之间的博弈。
拿我们部署一个70亿参数模型做知识问答为例。最早我们直接拿PyTorch原生的脚本部署,单张A100上并发只能到20左右,P95延迟却到了2秒多,压根扛不住线上流量。后来换用vLLM做推理引擎,通过PagedAttention把KV Cache的显存利用率大幅提上去,单卡并发轻松到了几百,P95延迟还降到了500毫秒以内。这个替换成本几乎为零,因为vLLM兼容HuggingFace模型格式,接口也走OpenAI风格,代码改动的量级很小。
推理部署时不建议一上来就整复杂的微服务架构。先用单引擎把核心接口调通,再逐步加缓存层、负载均衡、弹性伸缩。比较务实的优化顺序是:
- 先换高性能推理引擎(vLLM、TensorRT-LLM、Triton),优先解决显存和并发瓶颈;
- 再优化模型本身(量化、剪枝、蒸馏),比如把FP16换成INT8或者FP8量化,速度能再翻一倍,但要注意精度跌损;
- 然后再谈集群层的弹性伸缩,比如根据队列长度自动扩容Pod,高峰结束自动缩容,减少空闲GPU的浪费。
这块有一个特别需要注意的点:推理服务的内存和显存预估远比训练复杂。训练时只要显存放得下batch就行,推理时显存既要放模型参数,又要放动态变化的KV Cache,还要留一点给输入输出的中间态。用vLLM时要设置好max_num_seqs和max_num_batched_tokens,这两个参数直接决定了并发吞吐和显存占用。我的经验是先用python -c "import torch; print(torch.cuda.mem_get_info())"看空闲显存,再根据模型大小反推KV Cache的余量,宁愿保守一点也不要OOM。
3.3 模型版本和数据集管理:没人在意但早晚出事的环节
训练推理都是高光时刻,模型版本管理这类"地下室工作"最容易被人忽略。但我要说,这个问题一旦爆发,往往是灾难级的。
比如你把一个模型上线了,用户反馈效果变差,你需要快速回滚到上一个版本。如果没有模型版本管理,你根本不知道上一个版本在哪台机器的哪个目录里。又比如你用了一批新的数据重新训练,结果效果更差了,你想排查是不是数据清洗环节出了问题,但连数据集的hash都没记录,根本无从下手。
我的做法很简单:
- 模型产物统一用对象存储,目录按
模型名/版本号/时间戳组织,版本号用语义化规则(比如v1.0.0),每次发布都生成一个清单文件,记录模型结构、训练脚本commit hash、数据集版本、超参数; - 数据集每次清洗完就计算一个
md5或者sha256存下来,训练任务启动时校验数据版本,防呆; - 推理服务部署时,把模型的版本打进镜像的tag或者环境变量里,确保线上跑的是哪个模型一目了然。
这些活儿看起来脏乱累,但真正出现线上事故时,能让定位从"好几小时"缩短到"十几分钟"。
4. 可观测性与成本治理:让算力花得明明白白
4.1 监控到底该看哪些指标
可观测性这块,不少团队的监控面板花花绿绿几十个图表,但真出了问题,还是靠工程师登服务器敲命令排查。我总结出来一套"少而精"的监控指标体系,给大家参考。
GPU层,核心指标是SM利用率、显存带宽利用率、显存占用、温度、功耗。注意,SM利用率不等于GPU-Util,GPU-Util只是"某个采样周期内有没有活干",SM利用率才是"计算单元有多忙"。显卡温度超过85度就要警惕,超过90度大概率是散热出问题了,性能会明显下降。
任务层,要看训练吞吐(比如每秒处理的样本数)、单步耗时、loss曲线是否收敛。吞吐掉了一半,模型和数据可能没问题,反而是基础设施出事了。
基础设施层,要看CPU负载、内存、磁盘IO延时、网络重传率。网络重传率这个指标特别容易漏,多机训练时如果重传率高,通信效率基本报废。
我的建议是监控指标宁可少但必须可解释。每个指标都要能回答"如果这个指标变成红色,我应该怎么排查"。如果做不到这一点,指标再多也只是给值班同学徒增噪音。
4.2 成本归因:从"一笔糊涂账"到"一张明白表"
AI-Infra里最容易被业务方吐槽的就是成本。老板问:"上个月GPU费用怎么涨了30%?"如果你答不出来,这个锅就是你的。
成本归因的前提是把资源打上标签。K8s里给每个队列、每个团队、每个项目打Label,然后用量数据定期汇总到一张表里。最少要做到三个维度:团队维度、应用维度、时间维度。
比如我会定期跑一组指标:每个团队本月GPU使用总时长、平均利用率、单任务平均成本。这里有几个有意思的反直觉经验:
第一,利用率高不等于成本低。一个团队每天把A100占满跑一堆低价值实验,另一个团队每天只用两三个小时跑核心业务,前者的账单是后者的好几倍,但产出可能远不如后者。
第二,按需实例和包年包月(或Spot实例)的搭配很关键。K8s可以配置节点池的弹性伸缩,稳定负载用包年实例,突发负载用按需或抢占式实例。这个策略能把成本降低20%到40%。
第三,不要忘了存储和网络带宽的成本。很多人只盯着GPU费用,结果发现账单里数据存储和跨区流量费也不少,尤其在多副本备份和日志长期留存上。
成本治理不是算总账,而是要能拆到每个任务、每个团队、每一天,形成环比和趋势分析。这样才能有理有据地和业务团队沟通"资源用得合不合理",而不是拍脑袋做决定。
4.3 告警治理:别让值班同学活成救火队长
告警是AI-Infra里最见功力的一环。我见过太多集群,告警一天几千条,值班同学疲于点确认按钮,真正重要的告警反而被淹没。
告警治理有三条原则:
第一,只告警需要立刻人工介入的事情。GPU利用率低不用告警,最多生成一个日报,让团队自己看;但节点宕机、任务大面积失败、推理服务P95延迟超过阈值,这些必须立刻告警。
第二,告警信息要足够定位问题。一条好的告警应该包含:出错对象(哪个节点/哪个任务)、关键指标值、时间、可能影响的业务、以及一条排查入口链接。
第三,告警要有消除动作和升级机制。低级告警自动恢复后自动清除,高级告警如果15分钟未被处理就要升级到更高级别的负责人。不然高峰期的告警错过后,影响到业务才发现就晚了。
我自己的实战配置里,告警指标只保留了不到20个,但值班同学比我单独看几十个图表更快能发现异常和处理问题。这是做AI-Infra最容易被低估的价值。
5. 常见问题排查与避坑指南
5.1 问题速查表
这里把我这些年踩过的坑和群里常见的求助问题整理成一张表,大家可以保存下来当手册用。
| 症状 | 可能原因 | 快速排查手段 |
|---|---|---|
| 训练速度突然变慢 | 数据加载卡顿、NCCL通信性能差 | 用nvidia-smi dmon看SM利用率,跑nccl-tests的all_reduce测带宽 |
| GPU显存OOM | batch size过大、KV Cache设置过高 | 用--shm-size加大共享内存,调整max_num_seqs,开启显存动态分配 |
| 多机训练不收敛 | 批量大小变了但学习率没调、不同节点数据分布不一致 | 检查是否设置了正确随机种子,确认DataLoader的shuffle和分布式sampler用法 |
| 推理服务偶发超时 | 线程池阻塞、显存碎片化、模型加载冷启动 | 查引擎日志,看请求队列长度,用预加载或开启continuous batching |
| GPU-Util高但训练速度慢 | 计算强度低,卡在内存带宽 | 换用更高效的算子或减少tensor core的浪费比例 |
| 任务排队但集群显示空闲 | 资源预留、亲和性导致有GPU不能用 | 用kubectl describe node和kubectl get pods检查是否有Pending的Pod占着资源 |
5.2 我踩过的几个典型大坑
第一个坑是共享内存没设置够。Docker默认的/dev/shm只有64MB,但PyTorch DataLoader的多进程数据加载会把共享内存写满,导致任务莫名其妙地卡死或者报错。解决方案很简单,启动容器时加上--shm-size=8G,或者换成--ipc=host。这个坑特别隐蔽,因为不是每次都报OOM,而是时好时坏,非常难排查。
第二个坑是配置文件与代码版本不同步。有次我把一个训练任务的batch size从32改到64,但忘了更新配置文件,结果线上任务用旧配置跑了整整两天,产出结果全部作废。从那以后,我强制推行"所有训练参数都写在配置文件中,代码启动时读取并打印生效值"这个原则,绝不允许在代码里硬编码超参。
第三个坑是推理服务的优雅退出没做好。K8s在Pod被删除前会发SIGTERM,但如果推理服务没有处理这个信号,正在处理的请求就会被直接掐断,用户侧就是"偶发报错"。后来我在服务里加了信号量处理逻辑,收到SIGTERM后先把正在处理的请求跑完再退出,再配置terminationGracePeriodSeconds给足时间,这个偶发错误彻底消失。
5.3 新手起步建议:从一套能跑通的方案开始
对于刚接触AI-Infra的工程师,我的核心建议是:不要一上来就追求大而全的平台和框架,先在一台有GPU的机器上把模型训练和推理跑通,再逐步加调度、加监控、加成本治理。
具体可以按这个顺序来操作:
第一步,单机单卡。选一个自己熟悉的小模型(比如一个简单的BERT或者其他几亿参数模型),用PyTorch或TensorFlow完整训练一个任务,学会看nvidia-smi、学会解决OOM、学会调DataLoader。
第二步,切到容器化。把训练代码装进Docker,用Docker启动训练任务,搞清楚GPU挂在容器里是怎么透传的(--gpus all),搞清楚镜像怎么管理版本。
第三步,本地用Docker Compose或者单机K8s启动一套推理服务,接入vLLM或Triton,学会看延迟指标。
第四步,多机多卡。用两台机器跑分布式训练,配置好NCCL,学会看网络通信的日志。
这四个阶段走完,你对AI-Infra的整个链路就有了一个非常具象的认知。这时候再去看那些大型平台架构的文章,你会发现很多东西你之前没有概念的地方突然都能对上号了。
做AI-Infra这个方向,最忌讳的就是纸上谈兵。架构图画得再漂亮,不如亲自把一张卡跑满再跑坏,又把它修复的过程。我见过很多算法工程师转型做Infra,最后成功的,无一例外都是愿意蹲在机器前看日志、看监控、看底层状态的。这不是天赋问题,而是投入时间的问题。
最后再分享一个个人体会:AI-Infra的工作价值,很多时候不是某个性能指标从80%到99%的爽快,而是让整个团队一个月不用找你处理问题。那种"系统稳定到让人忘记它的存在"的感觉,才是这个方向真正精进的地方。如果哪天你的业务同学跑过来说"训练任务太顺了,我都忘了你在做Infra",那就是给你最大的夸奖。