恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
GPU集群调度器深度解析:从资源分配到万卡训练实战
首页
资讯中心
/
GPU集群调度器深度解析:从资源分配到万卡训练实战
GPU集群调度器深度解析:从资源分配到万卡训练实战
发布时间:2026/9/11 13:17:59
大家平时聊大模型训练焦点总在 GPU 型号、显存大小、互联带宽这些硬件上。但真正把一万张卡组织起来、让它们别闲着、让训练任务别互相打架的其实是调度器。调度器不产生算力但调度器决定算力被谁用、怎么用、用到什么程度说它是训练场的隐形老板一点都不夸张。这篇文章是 AI Infra 系列训练与调度专题的下半部分核心就聊一件事当 GPU 规模从一两张卡膨胀到几千甚至上万张时调度器是怎么完成排班的。我会结合自己在大规模训练集群上的实操经验把调度器的核心职责、关键机制、常见坑和落地选择都过一遍争取让刚接触 Infra 的算法同学能看懂也让已经在做集群管理的朋友能从我踩过的坑里找到点参考。如果你是只跑过单卡或者几卡训练的人看完这篇文章你大概也能理解为什么大厂要专门养一个团队去伺候集群调度。1. 先搞清楚调度器在 AI 训练里到底管什么调度器的职责听起来简单把 GPU 资源分给训练任务。但分资源这件事在万卡规模下会拆出一堆让人头疼的子问题。理解调度器先得理解它管的几件基本事。1.1 排队谁先上车GPU 是稀缺资源训练任务往往多于可用卡数所以调度器第一个职能是排队。谁来排队、排队排多久看起来只是先来后到的问题实际上牵扯到公平性和效率的平衡。举个例子一个团队提了一个需要 512 卡的任务另一个团队提了 8 个需要 64 卡的任务。如果集群刚好有 512 卡空闲从资源利用的角度看接大任务能立刻让所有卡跑满但如果 512 卡任务只有 300 卡的数据调度器就得等剩下的卡凑齐这个空闲等待窗口就是纯粹的浪费。反过来如果优先跑小任务就能立刻用满卡但大任务的 512 卡需求会一直悬着占着的配额又让其他团队眼馋。调度器要做的就是在这种矛盾中找一个大家都还能接受的排队策略。我见过很多初建集群的团队调度策略简单粗暴就是 FIFO 先来先服务结果一个大任务堵住所有小任务公司内部的算法同学为了抢卡天天在群里吵架。后来调整成带优先级的队列模型大任务和小任务分队列跑情况才缓解。1.2 分配把卡分给谁、怎么分排队之后是分配动作。分配不是简单地把 N 张卡划给你而是要回答三个问题。第一分配哪些具体的卡。这涉及到 GPU 的拓扑结构。训练任务尤其是大模型训练对卡间通信带宽极其敏感调度器最好把同一个节点上的 8 张卡分给同一个任务因为 NVLink 互联的带宽远高于网卡互联。如果同一个任务的卡散落在不同节点跨节点通信走 InfiniBand 或 RoCE延迟和带宽都会打折训练效率可能下降 20% 甚至更多。第二怎么保证资源不浪费。一张 80G 的卡跑一个只需 40G 显存的任务剩下的 40G 是不是能用如果调度器支持 GPU 显存级别的切分就能把一张卡分给两个任务把小任务挤压到大卡的剩余空间里。但切分本身有代价显存隔离不干净会带来稳定性风险所以很多集群宁可不切也不能让两个任务共享一张卡。第三怎么处理超卖。有些调度系统为了提升利用率允许任务申请的资源超过实际物理资源赌的是任务不会同时用满。这个策略在 CPU 集群里常见在 GPU 集群里风险极高因为训练任务对显存和带宽的使用都比较激进超卖一旦翻车就是 OOM 或者性能互相拖累。我在生产环境基本建议关闭 GPU 超卖宁可利用率低一点也要保住稳定性。2. 为什么手动分卡玩不转万卡集群有人可能会想GPU 分配能不能靠人工小规模当然可以两三个人管几十张卡拿个表格登记一下就完了。但到了几百卡、几千卡人工分配会撞上三个绕不开的墙碎片、优先级和亲和性。2.1 资源碎片一万张卡也会不够用集群里的碎片问题和内存碎片类似但更复杂。调度器要把一个个任务安排进 GPU 池里挑卡的过程如果不去全局考虑最终会出现一种尴尬局面——每张卡都剩一点显存或者剩余一点算力但单独任何一张卡都不够满足一个大任务的需求大任务只能在碎片里浪费排队时间。举个例子假设集群有 100 个节点每个节点 8 张 A100。现在来了 5 个 16 卡任务、10 个 8 卡任务如果调度器只是机械地按节点顺序填很可能把大量节点填得剩下 4 卡、2 卡这种残片等到一个 32 卡的大任务来了发现表面空闲卡数够但分布太散凑不齐一个连续拓扑任务根本没法正常启动。所以我一直主张调度器要有打包意识把小的任务尽量集中放置留出连续的节点块给大任务。这个思路听起来简单要在代码里实现好却需要精心设计评分函数和分配策略。2.2 优先级和抢占紧急任务怎么插队训练场景里的优先级问题远比想象中复杂。大模型错题重训、线上事故后需要紧急回滚模型、重要客户有个 deadline 需求这些都会催生插队需求。调度器的抢占机制决定了一个新来的高优任务能不能把正在跑的低优任务挤走。抢占不是简单的杀死进程它要处理一堆善后问题被抢占的任务是不是要保存 checkpoint保存完再杀还是直接杀被杀的任务重新排队后要不要补偿优先级如果被抢占的任务已经跑了 10 个小时就这么杀掉浪费的算力算谁的合理的做法是支持可抢占队列和不可抢占队列分层。核心重要任务跑在不可抢占区普通实验任务跑在可抢占区紧急任务来临时调度器优先抢占可抢占区的任务尽量不动不可抢占区。这样既保证灵活性也保住底线。2.3 亲和性要求卡和卡之间的人际关系不能乱调度器不但要管资源量还要管资源的位置关系。训练任务对多卡之间的通信拓扑有要求细说起来包括同一任务的卡最好在同一个交换机下面跨交换机通信会绕路带宽损失明显同一任务的卡最好集中在同一个机柜机柜内延迟最低多任务之间的卡尽量分散避免两个任务互相争抢同一台交换机的带宽。这些都是拓扑亲和性约束。调度器在分配时要像一个房产中介既要保证客户预算范围内有房住还要尽量让客户的公司离地铁站近。这种多维度的优化人工排卡想都别想。3. 主流调度方案的选型对比调度器不是非得自己写。业界的成熟方案已经不少关键是适不适合你的场景。我按自己的理解把主流的几条路线归归类顺便聊聊它们各自的脾气。3.1 Kubernetes 系Volcano、Kueue 和 Karmada现在的 AI Infra 团队多数会基于 Kubernetes 做集群管理。K8s 本身提供的基础调度器偏向微服务和 Web 负载处理训练任务时很多高级能力不够于是衍生出不少专用方案。Volcano 是其中比较能打的一个它提出了Job的概念把一组 Pod对应分布式训练的一组进程打包成一个整体进行调度。Volcano 支持 gang scheduling、队列优先级、抢占、预留等能力是目前国内很多大厂训练平台的基础组件。它的好处是社区活跃相关案例多遇到问题容易找到参考。缺点是在超大规模集群比如单集群上万节点上调度性能还是会遇到瓶颈需要做一些扩展。Kueue 是 Kubernetes SIG 下的项目它把重点放在多租户配额管理上适合做集群容量编排。Kueue 本身不做资源调度而是控制一个 Job 什么时候能不能被调度用 Admission 机制先把 Job 卡在队列里等配额满足再放行。它的模型更适合把 K8s 当作统一资源池然后按部门、按项目切配额。和 Volcano 比Kueue 在调度细节上弱一些但在租户资源治理上更强。Karmada 则是多云多集群的管理方案。训练集群如果混合了自有机房、公有云、边缘资源Karmada 可以做跨集群的资源分发和调度。不过对于大多数自建训练场Karmada 的引入成本和复杂度都偏高除非确实有混合云的强需求否则不用急着上。3.2 SLURM传统 HPC 的常青树SLURM 是老牌 HPC 调度器学术机构和高性能计算中心用得非常多。它的资源抽象比较朴素就是节点、分区、任务三件套调度策略有 FIFO、Backfill、抢占等选项。如果你团队的人习惯用 sbatch 提交作业、用 squeue 查排队SLURM 的上手成本非常低。SLURM 的优势是稳定、简单、运维生态成熟尤其在纯 MPI 和传统 HPC 场景几乎没有对手。但在 AI 训练场景里它对容器支持、GPU 高级特性、动态资源调整的支持相对弱一些需要额外做一些封装。我自己见到的情况是很多大厂虽然内部主调度用 K8s 系但边缘的 HPC 集群仍然用 SLURM 维持运转两边通过网关打通。3.3 自研调度器大厂最后的归宿当集群规模上万、任务类型从训练扩展到推理、数据预处理、在线评测且需要与内部 CMDB、配额系统、计费系统深度绑定开源方案的定制成本会越来越高。不少公司最终会走向自研调度器或者在开源方案上层做一些 deep fork。自研不是炫技而是被需求逼的。比如集群要同时调度 GPU 裸金属和云虚拟机比如调度策略需要做到精确到卡和显存级别的精细切分比如调度决策需要参与训练拓扑的自动设计——这些需求在开源项目里很难全部打通。但自研也意味着巨大的维护成本只要走上这条路就得接受一个现实你们不再只是一个训练平台团队而是一个基础设施团队。4. 调度器落地实践队列、抢占和碎片整理的细节选型只是第一步真正让调度器好用的是落地时的细节调优。我把几个实战中容易踩坑的关键点单独拿出来说。4.1 队列和优先级应该怎么设计队列设计没有一个万能公式但有一个大致的思路可以遵循。按任务角色分至少要有交互式调试队列、短任务队列、长训练队列、紧急任务队列。交互式调试队列的资源配额少、优先级高专门给开发同学连上去看代码、测环境短任务队列给数据并行的小规模训练跑完即走长训练队列给大模型预训练任务可能跑几周需要的是稳定和不可抢占紧急任务队列平时不启用一旦启用可以抢占短任务队列的资源。优先级方面我的经验是不要把所有任务都设成高优。按高优任务数量 5%这个比例控制否则抢占机制会频繁触发整个集群陷入任务还没热身就被杀了排队重来的恶性循环。调度器频繁抢占的代价比你想的大得多每次抢占都是一次训练任务的冷启动checkpoint 加载、数据集 shuffle、系统预热这些环节加起来可能浪费几十分钟。另外一个容易被忽略的点是配额和队列的绑定粒度。我见过一些团队把配额设到部门维度而不是项目维度结果部门内部的项目之间又开始抢资源。建议配额至少做到部门 项目两层可以的话再细分到任务模板维度这样能减少很多内部资源摩擦。4.2 抢占策略的参数细节抢占策略在开源调度器里有很多参数实际配置时要注意几个关键点。第一抢占的检测周期。调度器不能每秒钟都去检查有没有更高优先级的任务在排队这样开销太大。一般设置 10 到 30 秒的检测周期但紧急任务队列的检测周期要更短可以单独开一个快速通道。第二抢占的选择策略。当一个高优任务需要 64 卡而集群里有 10 个 8 卡任务在跑到底抢哪几个从资源利用角度抢最少的任务、凑够 64 卡最划算但从公平角度反复被抢的倒霉蛋会很难受。好的策略需要考虑任务的已运行时间、Checkpoint 频率、预估还要跑多久等因素。比如已经跑了 90% 的任务即使优先级低也不建议抢它马上就结束了抢了反而浪费之前的计算。第三抢占的幂等性。调度器发出抢占指令后目标任务不一定能立刻退出可能卡在保存 checkpoint 的状态里或者退出失败。调度器需要有超时和重试机制而且要处理抢占指令已经发出但资源还没释放时的状态同步否则会出现资源分配出去但实际不可用的情况。4.3 碎片整理的实操方案碎片整理是调度器优化的硬骨头。我见过的比较有效的实践是给每个节点打一个拓扑标签记录节点上有多少卡被分配、剩余卡是连续的还是分散的、剩余显存总量和分布。调度时给任务分配节点的时候增加一个连续性检查如果任务申请 8 卡优先找剩余卡恰好是 8 张且空闲卡在同一节点内的资源如果任务申请 16 卡优先找 2 个节点空闲 8 卡的组合而不是 4 个节点空闲 4 卡的组合如果任务只需要 1 张卡允许它放进任何节点剩下的碎片位。这种简单的连续性检查配合节点打分排序就能有效抑制碎片扩散。更高级的做法是引入周期性的碎片整理任务——把节点上零散的小任务迁移合并腾出完整节点。但迁移训练任务本身有风险一般只在集群低峰期做而且要保证迁移流程不影响任务有效性。5. 万卡集群的调度器架构设计万卡集群的调度器已经不只是一个分配器而是一个复杂的分布式系统。架构设计上我重点讲两个点两级调度和容错重调度。5.1 两级调度全局调度和本地调度的分工当集群有上万张卡全局只有一个调度器实例去管理所有节点性能和扩展性都会出问题。常见的解法是两级调度。全局调度器也称协调器负责全局资源状态的管理、配额的控制、任务的整体准入。它不直接接触每一张卡的具体分配细节而是把任务下发给某个区域调度器。区域调度器负责自己管的那片节点的具体资源分配。区域之间的资源状态定期汇总到全局全局基于汇总信息做跨区域的负载均衡。这样做的优势是显而易见的。首先调度器之间的通信压力大大分散单点性能瓶颈降低其次一个区域调度器出问题只会影响该区域的调度不会拖垮整个集群再次资源配额可以在全局统一控制同时具体的资源调优可以在区域内部完成职责清晰。两级调度带来的挑战也不小最典型的问题是全局状态和局部状态的不一致。全局调度器可能根据过期状态做决策把任务下发给一个已经没有足够空闲资源的区域。所以区域调度器必须有接不住就反馈的能力把任务退回给全局由全局重新分配。这个反馈机制的延迟和重试逻辑要设计得足够稳。5.2 容错调度器挂了怎么办调度器本身的容错比任务容错更容易被忽视。训练任务挂了可以重启调度器挂了整个集群的任务都处于失管状态。调度器自身必须做成多副本的用主备模式或者选主模式保证高可用。主备模式下主调度器的心跳丢失后备调度器要能在几十秒内接管。接管时要处理的关键问题是恢复任务和节点的状态对应关系。几万个 Pod 和几万个节点重启一个调度器进程就要重新收集一遍所有节点资源信息和任务状态这个恢复过程本身耗时很长。为了加速调度器会把状态增量实时持久化到 etcd 或者其他存储接管时只要重放增量日志就能快速恢复。还有一个处理不好容易出大事的环节任务和调度器的连接。分布式训练任务跑起来之后如果和调度器断开连接任务本身不受影响继续用自己已分配的资源跑着但调度器内存里的状态已经和目标任务失联后续所有操作比如缩容、抢占、抢占恢复都会变得不可靠。这要求任务侧有一个 agent 组件负责向调度器持续上报心跳和状态。agent 和调度器之间的连接断开时双方都要有超时保护机制不能互相等待。5.3 动态扩缩容云的弹性怎么用最后说说动态扩缩容。自建机房的资源是固定的调度器只要管好静态资源。但混合云的场景下调度器要具备动态增加节点的能力。常见的模式是当某个队列的任务排队时间超过设定阈值调度器触发云上扩容请求通过云 API 新开一批 GPU 实例实例在调度器里注册成为新的节点任务就开始调度到这些新节点。当队列空闲调度器又要把云上的节点释放掉节省成本。这时的调度器更像一个资源经纪人它要在任务需求和成本预算之间取平衡。操作层面有几个难点一是云上实例的类型和规格要和本地集群兼容比如网络能不能打通、镜像能不能通用二是扩容的预期管理云上开节点需要几分钟任务排队等待的时间可能会超过算法同学的耐心三是缩容时机的判断不能太敏感不然会出现扩了又缩、缩了又扩的抖动白白给云厂商送钱。我建议缩容的逻辑要加入一个冷却期节点空闲超过 30 分钟才释放避免因为任务调度的短时空隙引发不必要缩容。6. 调度器日常运维的几个经典问题与排查实录调度器的运维是一门经验活我这里挑几个自己实际碰到过的高频问题整理成一张速查表后面慢慢展开讲。现象可能原因排查方向任务排队很久但不调度资源配额不够 / 资源碎片化看队列配额、看空闲资源分布、查是否有大任务占坑任务被杀后状态一直卡在 Terminatingagent 失联 / checkpoint 保存中检查 agent 存活、检查进程退出状态、手动清理节点状态异常但训练还在跑心跳丢失 / 网络抖动检查节点 agent 日志、网络连通性、kubelet 状态调度器发指令后任务没反应指令版本不兼容 / 超时设太短检查指令协议、任务侧 agent 版本、超时参数两个区域的负载严重不均全局调度状态滞后 / 区域权重设置问题看全局资源汇总频率、区域调度器的日志高优任务频繁抢低优但集群效率降低抢占过于频繁 / 被抢任务重启次数多增加不可抢占队列、降低高优任务比例、调整检测周期6.1 任务排队但不调度先别急着找调度器问题这个现象最容易让新运维抓狂明明看集群资源有空闲任务却一直不跑。真正的原因往往不是调度器不努力而是任务根本没达到调度的条件。我举一个实际经历。当时一个 128 卡的训练任务一直排队我们一批人去查调度器日志看起来都没毛病。后来才发现任务申请的内存资源是每个 Pod 128G但集群节点的内存只有 96G 可分配根本没有节点能满足这个规格。这类问题在调度器里叫资源请求不匹配它不做任何报错就是安静地等待。排查这类问题的标准动作是先看任务请求的资源含 GPU、CPU、内存、显存和节点可分配的资源是否匹配再看是否有节点亲和性或者污点容忍的约束不满足最后看任务的配额是否被部门消耗完了。这几个维度都过一遍基本能找到原因。6.2 抢占后任务状态异常多半是退场流程没处理好训练任务被抢占后需要优雅退出保存 checkpoint 是其中最重要的一步。但很多情况下任务里的训练脚本并没有处理外部终止信号或者处理逻辑写得不对。比如 PyTorch 的 DDP 训练脚本如果直接 kill 掉主进程其他进程可能还活着状态就会变得乱七八糟。正确做法是在训练脚本里注册信号处理器收到调度器发来的信号后先存一次 checkpoint再通知所有分布式进程退出最后统一退出。如果每个进程各自为政很快整个任务状态就乱了。排查状态异常时先看任务的退出日志里有没有 checkpoint 保存记录。有保存记录的可以放心重启没有保存记录的就要考虑检查数据一致性有时候甚至得手动清理残留进程、释放 GPU 显存才能重新调度。6.3 节点失联先看 agent 再看网络节点失联是万卡集群的日常问题几千个节点里总有一个两个掉线的。我的排查顺序是先看节点 agent 进程的存活情况再看 agent 和调度器的网络连接最后看节点的硬件状态。有次我们遇到一个节点状态显示异常但训练任务还正常跑着。一查才发现agent 因为一段内存泄漏问题死掉了但训练进程和调度器之间用的是独立连接所以任务不受影响。这种半失联状态最危险因为调度器会认为节点资源不可用可能把新任务调走但老任务还在跑资源实际上是双倍消耗。处理方法是把 agent 做成独立的守护进程崩了能自动拉起同时心跳上报频率要合理太频繁会增加开销太慢会延迟发现故障。6.4 调度性能下降查日志不如看指标当集群规模大了调度器的性能问题会逐渐暴露。调度一个任务要好几秒或者调度队列里的任务越积越多。这时候翻日志找线索效率太低我更建议直接看几个核心指标调度器每秒处理的调度决策数、任务平均排队时间、调度器 API 的响应延迟、etcd 的读写延迟。调度性能瓶颈通常出在两个地方一是资源状态缓存过期导致频繁的缓存刷新二是调度算法本身的复杂度在大规模下指数级上升。前者可以通过扩大缓存、降低刷新频率来优化后者可能需要引入分级调度或者预筛选机制把不可能的节点在早期就排除掉。7. 调度器后面还能怎么进化聊了这么多最后说说我个人的体会和方向。调度器在 AI Infra 里属于那种做好了没人夸做砸了全是锅的部分。但它确实决定了训练场的整体效率一个好的调度器能让集群利用率保持在高位同时还能让大家排队等得心平气和。我自己在实际操作中最大的体会是调度器的设计一定要贴合自己公司的业务形态别人的最佳实践只能参考不能照搬。比如有的公司重视训练效率有的公司重视成本控制有的公司重视多租户隔离不同重点会让调度策略的取舍完全不一样。如果后续要做扩展我个人看好三个方向一是智能调度通过历史任务数据预测任务运行时长和资源占用提前做出调度决策二是异构资源协同把 GPU、CPU、内存、网络带宽放在同一个调度模型里统一考虑而不是各个资源独立规划三是训练-推理混合调度让推理任务和训练任务在同一套集群上错峰使用这样能够显著提升整体资源利用率。调度器这个领域远没到终局谁能让资源像水一样自然流动谁就能在 AI Infra 这场竞争里获得不小的优势。最后再分享一个小技巧如果你在维护一个训练集群记得给调度器本身也设置监控和告警不要只盯着 GPU 利用率。调度器的 CPU 使用率、内存占用、任务调度时延这些指标有时候比 GPU 利用率更能提前暴露问题。调度器也像一个需要照顾的伙伴它的状态健康了整个训练场才能转得顺畅。