ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

GPU训练集群调度核心机制与实战:从排队到满组调度

2026/9/11 15:32:03 拓冰建站 浏览量
GPU训练集群调度核心机制与实战:从排队到满组调度 一万张 GPU 怎么排班这问题听着像段子但凡是管过千卡以上集群的 AI Infra 老哥都知道这不是玩笑。我这些年看着 GPU 从实验室几块卡一路涨到公司上万卡调度器在里面的位置也越来越微妙——初期它就是个小工具跑通了就行等到集群规模上去之后你会发现整个训练场里最忙的不是某个训练任务而是调度器这个“隐形老板”。它决定你提交的训练什么时候能跑、跑在哪批卡上、能不能跑完甚至在你毫不知情的情况下把你的任务排到半夜三点。这篇文章我就把自己在 AI Infra 训练与调度方向上的踩坑与设计思路聊透适合正在搭训练平台、管 GPU 集群、或者单纯想搞明白“一万张卡到底怎么分配”的朋友。1. 为什么调度器才是训练场的“隐形老板”1.1 规模上去之后最先崩掉的是人工协调先说一个很真实的场景。团队刚起步那会儿几十块 GPU任务好协调谁要跑什么群里喊一句大家互相让一让数据并行拆几卡搞定。这个过程非常“有人情味”但也很脆弱。等集群到了几百卡你发现群里全是“谁在用那批 A100”“训练任务怎么又 OOM 了”“哪位兄弟把节点搞挂了”——信息爆炸人情协调彻底失灵。到了千卡、万卡这个量级人工协调已经完全不可行了原因很朴素人脑没法同时管理那么多任务的启停、资源的分配、优先级的切换、以及故障节点的隔离。这时候就出现了调度器。它在整个 AI Infra 体系里的角色有点像一个集团公司的会议室管理员整层楼就一个大会议室但几十个部门几百号人天天要开会谁先订、谁能让、谁必须准点开完不可能让各部门经理自己吵必须有一个规则明确的行政中枢来排。调度器做的就是这件事——你把训练作业交上去它告诉这个作业你排在几点、争取哪个会议室GPU 节点、可以借用哪些设备显存、带宽、网卡。1.2 谁先跑、跑在哪、跑不了怎么办调度器核心要解决的问题仔细拆下来其实就三个谁先跑多个训练任务同时提交怎么定优先级。是按提交时间先来后到还是按业务重要程度或者按某个团队剩余的配额来动态调整。跑在哪这个任务需要什么资源——几卡、多少显存、是否需要 RDMA 网络做分布式通信——然后从集群里挑出一批满足条件的节点组成一个执行环境。跑不了怎么办资源不足的时候任务放在队列里等着等有人释放了资源再调度上去等的时候任务不能死得让它“挂起”在那里时机合适就立刻拉起来。这三点听起来简单真要在大规模集群上做好每一个都是深水区。比如“跑在哪”这件事一万张卡分布在几百个节点里节点之间的网络拓扑是不一样的同一个机架内的 NVLink 带宽高跨机架走 RDMA 延迟高。调度器如果只按“还有几张空闲卡”来分配不考虑拓扑那跑出来的大模型训练任务通信效率可能差一大截。1.3 “隐形老板”的权力到底有多大我做 AI Infra 这些年最大的感受就是调度器看似只是个“排队的程序”但在大规模集群里它的地位一点都不比业务方低。因为调度的结果直接决定了资源利用率同样一万张卡调度策略好平均利用率能到 70% 以上策略差可能只有一半卡在干活其他卡要么空转要么被零散碎卡占着没法用。任务完成时间一个紧急的 bug 修复需要立刻跑一遍增量训练如果调度器能把资源挤出来半小时就能出结果如果调度器不懂抢占任务得排到第二天早上。团队加班程度半夜调度器把训练任务杀了没有 checkpoint 恢复第二天模型组老哥一早过来看到 Loss 曲线断了整个人心态直接崩。调度器对任务生命周期的管理能力直接影响很多人的发际线和家庭和睦。所以在 AI Infra 这个圈子里大家常开玩笑说训练场里最辛苦的不是模型是调度器。模型只需要等着被训练调度器却要在每一毫秒里决定几千个任务的命运。2. 调度器里必须看懂的三个核心机制2.1 优先级与配额不是所有人都能“插队”很多刚接触调度系统的同学以为调度器就是先来先服务跟食堂排队打饭一样。真实场景里远远不是这样。大规模集群上跑的任务类型非常杂有耗时几天几夜的全参数预训练、有几十卡的中型微调任务、有几分钟就能跑完的小规模实验、还有只在特定时段启动的周期性数据回流任务。如果所有任务一视同仁排一个队那一定是最早提交的一批“大块头”任务把卡全部占满后到的紧急任务只能干瞪眼。所以成熟的调度系统里必须有“优先级”机制而且要区分几层第一层是调度优先级即同一个队列内谁先调度。高优任务提交时如果低优任务在等待高优可以直接插到前面。第二层是抢占优先级即高优任务提交时如果低优任务已经在跑了是否可以把低优任务挂起把资源腾出来给高优任务。第三层是资源配额即每个团队、每类业务最多可以占集群资源的百分之多少。配额的意义是防止某个团队一口气把集群全占了其他团队用不上。这个有点像一个楼里各公司租了不同的楼层——你可以在自己的楼层随便折腾但不能把别人的楼层也占了。实际配置优先级的时候我的经验是优先级层级不要设太多。我们曾经搞过九个优先级最后发现没人搞得清楚谁比谁高运维同学纯靠查表和背诵才能判断一个任务该排哪级非常蠢。后来收敛到四级紧急修复 核心训练 日常微调 低优实验。清晰简单大家都能理解调度器执行起来也高效。2.2 资源匹配从整卡到细粒度的选择调度器第二个核心功能是资源匹配。这个“匹配”看起来简单——有空闲卡就分配过去——但实际面临一个很经典的问题按整卡分配还是按显存容量细粒度分配大模型训练任务尤其是多机多卡分布式训练通常要求分配完整的 GPU。因为训练时每张卡上的进程都要参与集合通信all-reduce如果一张卡还同时跑着别人的推理任务显存和带宽都会互相干扰训练速度直接劣化。所以我们做训练调度时默认是整卡分配甚至要求整节点分配——一张节点 8 卡如果我只要 4 卡另外 4 卡空着也不能给别的任务用为的是保证网络拓扑完整避免通信局部性受影响。这一点和推理任务差异很大。推理场景里一个模型可能只需要 1GB 显存用 40GB 显存的卡去跑完全是浪费所以推理调度通常走细粒度分配甚至用上 MIGMulti-Instance GPU把一个物理 GPU 切成多个独立的小实例。这也是为什么 GPU 显存容量测算时训练和推理完全是两个思路推理测算的是单请求峰值显存训练测算的是模型参数 梯度 优化器状态 激活值的总体积。这里想多说一句很多用户问“GPU 显存容量到底按训练算还是按推理算”我的答案永远是看你的主要负载类型。如果集群里 80% 是训练任务显存规划必须保证训练能吃下最大模型如果纯跑推理那就按并发请求的显存占用总和来算。混部场景还得额外考虑隔离别让推理任务的显存抖动把训练任务搞崩。2.3 抢占与优雅中断调度器最考验功力的一环调度器最容易让人吐槽的就是抢占。抢占有两种冷抢占高优任务来了低优任务被直接杀掉腾出资源。简单粗暴但低优任务如果在训练中途被杀没有 checkpoint这几天就算白跑。热抢占也叫优雅抢占。调度器通知低优任务“你准备一下让出资源”训练框架先保存 checkpoint 再退出。低优任务虽然被挤掉但进度没丢恢复起来很快。在大规模生产环境里我一定建议用热抢占。宁可多花一点调度时间也要保证任务有体面退出的机会。真的你有过凌晨三点被训练任务中断电话吵醒的经历就会理解 checkpoint 和优雅退出有多重要。另外还要提一个概念gang scheduling中文常叫“满组调度”或“聚组调度”。大模型训练任务由几十甚至几百个进程组成这些进程必须全部调度成功任务才能真正跑起来。如果只调度成功 80%剩下的 20% 卡不到位已经启动的 80% 也只能阻塞等待白占资源。所以调度器必须支持“要么全给要么不给”的原子调度语义把一整组资源一次性分配到位再拉起任务。这一点是区分一个调度器能不能真正用于大规模 AI 训练的关键指标。3. 主流调度器选型不是越贵就越好3.1 开源生态里的几个常见流派我用过不少调度器可以说各有千秋适合的场景也完全不同。目前开源生态里最常见的几个选项Kubernetes 默认调度器kube-scheduler。这个调度器面向的是微服务和长时间运行的在线应用优势是生态成熟、稳定性高、和容器化结合紧密。但直接用在大模型训练上问题也不少它不懂 GPU 拓扑、不支持满组调度传统实现里没有 gang scheduling 的概念、对强占策略的支持也很弱。Volcano。这是基于 Kubernetes 的批处理调度系统可以理解成给 kube-scheduler 打了一套“AI 训练增强包”。它支持 gang scheduling、支持队列和优先级、支持抢占是目前 K8s 生态里做 AI 训练调度最主流的选择。我们内部很多训练平台都是基于 Volcano 扩展的。Slurm。这个更偏向传统 HPC高性能计算场景。如果你要让几千个 CPU 核跑数值模拟或者跑 MPI 任务Slurm 是老兵。它的调度策略比较朴素但稳定可靠很多老牌超算中心都在用。缺点是容器化支持弱、云原生适配少团队如果已经全面 K8s 化选择 Slurm 会有一定的摩擦成本。自研调度器。当规模大到开源方案撑不住有些头部团队会选择自研。比如把 K8s 的 scheduler 框架拿过来做二次开发或者干脆绕开 K8s 直接在资源管理层做调度。自研的好处是策略可以完全定制代价是要养一个专门的调度团队。3.2 为什么默认调度器不够用我见很多团队踩过同一个坑K8s 集群搭起来了GPU 也纳管了直接在默认调度器上跑训练任务跑着跑着就出事。最典型的是两个问题一是批处理任务调度效率低。K8s 默认调度器是按 Pod 一个一个调度的一个训练任务有几十个 Pod它一个个给它们找节点找到一半发现资源不够了已经排上去的那些 Pod 就得干等。没有满组调度的概念整体效率非常拉胯。二是优先级抢占机制弱。默认调度器虽然也有优先级但抢占逻辑很简单——抢到资源就杀根本不管你训练任务有没有保存进度。真跑起大模型训练这种粗暴抢占一次可能就让你的训练回滚好几个小时。所以我的建议很明确如果集群规模到了几百张卡以上不要直接在默认调度器上跑训练老老实实引入 Volcano 这样的专用调度系统或者至少确认你的调度器支持 gang scheduling 和优雅抢占。这块的投入绝对值得。3.3 不同规模团队的选择思路说到选型我习惯先把团队规模和资源规模摆出来几十卡的小规模团队用默认 K8s 简单队列规划就够了。这个阶段调度器的瓶颈不明显手动排查也来得及。几百卡的中等规模建议直接上 Volcano同时规划好队列和优先级。这个阶段一定要把调度策略设计好否则后面扩卡会很难受。上万卡的超大规模要么自研 深度扩展调度器要么考虑开源调度器和云厂商调度平台结合。这个阶段调度策略基本就是核心竞争力了每提升 1% 的利用率省下的钱都非常可观。顺带一提很多公司管训练任务之外还会引入工作流调度器比如海豚调度器这类负责编排“数据预处理 - 训练 - 评估 - 上线”这条流水线。它们的角色和本轮聊的 GPU 调度器不一样GPU 调度器管的是“资源怎么分配”工作流调度器管的是“任务流程怎么串”。两者不是一个层级但在实际的 AI Infra 平台里常常被一块提。希望大家别混了。4. 一万卡集群的调度设计实战4.1 队列设计的黄金法则前面讲了不少理论这一节落到实操。假设你手里有一万张 GPU几百个团队都在用怎么设计调度策略我的思路很简单按“业务线 任务性质”两个维度来划分队列。按业务线划分比如搜索推荐线、大语言模型线、多模态线每个业务线是一个独立队列有自己的资源配额。这样做的好处是业务之间互不干扰某个业务线再忙也不会把其他人的资源全占了出事的时候也好定位“是不是谁把配额吃完了”。按任务性质划优先级队列每条业务线下再把训练任务分成“核心训练”“普通微调”“实验训练”等不同优先级的子队列。用户在提交训练任务的时候选择对应的队列即可。实际上lora 训练这类对时效要求不高的任务我会建议放到低优队列哪怕慢一点启动也没关系而紧急的全参数微调大模型才应该走核心训练队列。实施的时候有一个很关键的指标叫驱逐占比eviction ratio。我们内部会实时监控高优任务抢占低优任务的频率如果驱逐占比太高说明低优队列经常被高优任务打断低优任务的产出效率会很低这时候就要考虑给低优队列一个“最低保障配额”保证至少有 20% 的资源不会被抢占。这个有点像企业里的管理层——核心项目要资源可以但不能把基础的日常项目全挤垮。4.2 让任务提交变得更“懂规矩”有了调度器之后用户提交训练任务的方式也会相应改变。以前可能就是“找运维同学要卡”现在是通过平台提交关键参数得填清楚。以我们内部的提交模板为例核心字段差不多是这样的调度优先级/队列任务进哪个队列决定它大概多久能被调度上。资源需求需要几张卡、每张卡显存多大、是否需要 RDMA。亲和性是否必须独占整节点是否和某个在线服务不需要混部。重试与恢复策略任务失败后是否自动重启是否启用 checkpoint 自动恢复。这块我特别想提醒一点不要把资源需求写得比实际需要的大太多。很多人为了保险明明只需要 4 张 40G 卡就能跑的训练硬是要填 8 张 80G 卡。最后的结果就是资源被浪费任务还排不上。实际上只需做好显存预估仔细算一下模型的参数量、batch size、优化器状态资源需求量是可以压得比较准的。我们的做法是给用户提供一个“资源预估小助手”输入模型规模和数据并行度自动给出建议的资源需求很大程度减少了浪费。4.3 一个调度日的真实流水账文字讲太多大家可能觉得抽象我拿一个调度日来串一串。早上 9 点模型组的小李提交了一个 lora 训练任务只要 4 张卡排队等待。因为资源充足几乎秒级调度成功任务开始跑起来。上午 10 点另一个团队提交了一个全参数微调大模型的任务需要 64 张卡。不巧的是集群里空闲的 64 张卡分布在不同的节点上网络拓扑不满足调度器就卡住了。如果你在界面里看任务状态会看到它一直是“Pending”。这个状况非常典型不是资源不够是“够但位置不对”。我们的解决方式是让调度器支持节点组亲和性——训练任务会优先选择之前跑过同一模型的节点尽量凑齐拓扑完整的节点组。中午 12 点搜索推荐线的核心训练任务需要释放一批资源但因为队列配额已经分配好了调度器只管在时间轴上分配不能擅自给谁减配额。这个逻辑关键时刻能保命否则两个核心团队可能因为资源问题当场吵起来。下午 3 点线上反馈一个紧急 bug需要一个增量训练快速验证。走的是紧急修复队列调度器检测到高优任务到来触发抢占把低优队列里一个正在跑但又没跑到 checkpoint 的实验任务优雅挂起。实验任务在几分钟内保存完进度释放了 32 卡紧急任务立刻调度上去。整个过程大概 20 分钟在线推理的兄弟拿到了模型晚上顺利上线修复。深夜 2 点一个老旧的训练任务结束了但显存还没完全释放节点 GPU 显示被占用了一小块调度器没法往这个节点塞新任务。值班的运维同学收到告警上去查了一下发现是残留进程kill 掉之后节点回归资源池调度器立刻把下一个排队的任务调度上去。这种一天下来你就能体会到调度器管的东西太杂了。它不只是“排队取号”那么简单还要管节点健康、拓扑亲和、任务恢复、配额限额甚至和在线推理任务的混部策略联动。这也是为什么我觉得“调度器才是训练场的隐形老板”这个比喻那么准确——表面上大家觉得在跟 K8s、YAML、训练框架打交道实际上真正决定你工作顺不顺的是那个在后台按照复杂规则做决策的调度系统。5. 模型训练调度里的高频事故排查5.1 任务一直 Pending 起不来这是被问过最多的问题“老师我的训练任务提交了三个小时一直是 Pending怎么回事”排查路径基本是按顺序来首先看调度器日志确认任务是不是被调度了。如果完全没有调度事件大概率是队列配额已经打满或者优先级太低排不上队。这种情况要么等要么让管理员调整队列配额。其次看是不是资源拓扑问题。任务要求 64 卡集群里空闲卡有 70 张但分散在不同机架上调度器凑不出一个完整的 64 卡拓扑就只能一直等。这种情况可以手动指定节点组或者降低亲和性要求。最后看节点状态。有些节点 GPU 驱动出问题调度器标记为不可调度这部分资源会被排除在外。用kubectl get nodes看节点状态就能发现端倪。我的经验是60% 以上的 Pending 其实是拓扑或者配额问题而不是真的“没卡”。所以排查的时候别急着加卡先看清楚队列压力和节点分布。5.2 模型动不动就中断恢复还慢任务被抢占之后如果容器被直接杀掉训练进程的退出码非 0调度器需要拉起新 Pod然后从 checkpoint 继续训练。这个流程本身不难难的是两点一是 checkpoint 不能只存到本地磁盘因为新的 Pod 可能调度到另一个节点上本地磁盘的数据就丢了。一定要把 checkpoint 保存到共享存储比如 NFS 或对象存储这样任何节点恢复都能读到。二是要设置合理的 checkpoint 频率。存得太频繁IO 和存储压力大存得太稀疏一中断就丢好几个小时进度。这个频率要看你的训练任务跑多快一般全参数预训练模型一小时存一次比较稳增量训练和小任务可以放宽到两小时一次。5.3 显存碎片化导致节点利用率虚高再聊一个很隐蔽的问题。调度器显示某节点 GPU 利用率 60%但实际跑新任务时发现显存根本不够新任务无法调度上去。这种“资源假饱”多半是显存碎片化或者残留进程占着显存没释放。我们内部做了一个巡检脚本定时检查所有 GPU 节点上是否有非预期进程占用显存。一旦发现残留进程自动 kill 并通知用户。别小看这个集群从几百卡增长到几千卡之后这种现象会越来越多靠人工清理根本不现实。5.4 高优任务总是被打断如果紧急修复队列经常抢占低优队列资源你会发现低优队列任务不断重试白白消耗集群资源。这里要回头看看驱逐占比的指标以及低优队列是否有最低保障配额。我会建议团队设置一个策略低优任务一旦被抢占超过三次调度器就把它移到等待队列的末尾不再参与重复抢占同时通知用户重新评估任务的优先级是否设置合理。我整理了一个高频问题速查表方便平时排查直接用症状常见原因快速处置任务一直 Pending队列配额满了 / 拓扑不匹配 / 节点不可用查看配额和节点状态检查调度事件任务跑一半被杀高优任务抢占 / OOM / 节点故障配置优雅抢占和 checkpoint 自动恢复节点显示空闲但调度不上去残留进程占显存 / GPU 驱动异常巡检清理残留进程重启异常节点高优任务反复拉起低优任务队列优先级设计不合理调整驱逐占比给低优任务设置最低保障配额训练效率上不去分配到的节点网络拓扑分散启用拓扑亲和调度尽量整节点分配资源告警频繁用户超量申请资源 / 队列配额过大引入资源预估工具收紧配额这个表的形式是我在实际运维中反复打磨出来的每次新同学加入团队我都会把这个表甩给他们先看一遍。它的价值不在于“解某一个具体问题”而是帮人建立排查的思维框架——先看调度、再看资源、最后看训练框架本身。6. 调度系统优化的几个进阶方向6.1 基于预测的调度从“被动响应”到“主动规划”做到一万卡这个规模调度器的“聪明程度”直接影响成本。我们内部做过一个很有意思的优化根据训练任务的历史执行数据预测每个任务大概会跑多久。调度器拿到预测信息后就可以“见缝插针”——比如某个 A100 节点要空出 2 小时才会被下一个大任务占用这段时间可以塞一个预计 1 小时跑完的小实验任务把空隙利用起来。这类基于预测的调度虽然看着复杂但收益很高。它本质上就是在把碎片化资源重新利用起来。我们实际上线后集群平均利用率提高了七八个百分点。6.2 混部与多级资源池还有一个方向是把线上推理和离线训练做混合部署。道理也很好懂在线推理任务有明显的峰谷波动比如白天流量高晚上流量低而训练任务可以容忍等待并且追求“跑完就行”不追求“立刻跑”。调度器把训练任务塞到推理任务的低谷期去填空两边都不耽误整体交付效率会高很多。当然混部的前提是隔离做得好。GPU 显存、CPU 核、内存、网络带宽都要做严格的资源隔离否则推理任务和训练任务会互相拖垮。我们目前的做法是给训练任务加一个“可被抢占”标签一旦在线流量上来训练任务随时会让位。6.3 故障自愈与自动重排调度器到了一定成熟度之后还要具备“自愈”能力检测到某张卡的健康度下降了或者 RDMA 网络延迟异常升高自动把这个节点从调度池隔离出去同时把已经排在上面的任务迁移到其他健康节点。这个能力看起来像是“运维”干的活但在大规模训练场景里它就是调度器的职责延伸。毕竟等运维同学半夜被叫起来手动隔离节点训练早就停了很久了。我个人的体会是调度系统做得好不好最后拼的就是这些“异常场景下能不能兜住底”的细节。任务正常排队谁也做得不错难的是集群里一半节点都有点小毛病时调度器还能不能保持整个训练场的稳定运转。这个领域后面还有很多可以写比如大规模分布式训练时的通信调度、GPU 虚拟化与共享调度的取舍、训练和推理混部时的成本模型等等。不过那些内容篇幅更长留着后续系列慢慢拆解。最后就分享一个落地建议如果你的集群已经超过两百张卡建议把调度队列和配额规则的设计当成一件正式的工程来推进找一个同学专门负责调度策略的维护与指标监控。别看这个岗位好像很边缘集群规模往上走之后它就是那个决定整个团队是按时下班还是天天救火的隐形老板。