十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

万卡GPU集群调度器深度解析:从排队机制到拓扑感知与资源优化

万卡GPU集群调度器深度解析:从排队机制到拓扑感知与资源优化 1. 先聊个反直觉的事GPU越多反而越需要排队把时间拨回单机训练时代。那时候跑模型流程非常简单nvidia-smi看一眼显存挑一块空卡CUDA_VISIBLE_DEVICES0 python train.py完事。机器是死的卡是看得见摸得着的谁占着哪块卡一清二楚。但到了万卡集群这个量级事情彻底变了。你面对的不再是几块卡的问题而是几千个工程师、几百个训练任务、一堆随时可能故障的节点、以及每秒钟都在变化的资源水位。这时候你发现最棘手的问题根本不是怎么把训练代码写好而是怎么让这一万张卡别闲着。我见过太多刚接触大规模训练的同学第一次进了 GPU 集群的管理后台直接被吓一跳——明明有几千张卡自己提交的任务却排在队列里一动不动前面还有几十个任务在等。第一反应是资源不够第二反应是平台有病。但真正在 AI Infra 这个领域待久了你会发现排队恰恰是调度器在干活而且干得比人靠谱得多。打个不严谨的比方一万张 GPU 的训练集群就像一个超大型三甲医院。每个训练任务都是一个病人GPU 就是手术室调度器就是那个手里攥着手术室排班表的总护士长。没有排班系统的时候每个医生都自己冲进手术室抢位置看起来谁都能干活实际上手术室利用率低得吓人碰上急诊高优先级任务更是乱成一锅粥。有了调度器所有手术都得走排班流程——谁先进、谁紧急、这台手术需要几间手术室、做完之后哪间空出来给谁全是它说了算。这就是本文要聊的核心在大规模 AI 训练场景下调度器到底在做什么它凭什么决定你的任务什么时候跑、跑在哪、跑不跑得起来这个主题对应的是 AI Infra 系列训练与调度部分的下半篇。上半篇我们拆过训练任务本身的资源模型——一个任务要几张卡、每张卡多少显存、怎么通信、怎么同步。下半篇的重点就一个字排。把成千上万个任务排到上万张卡上让整个集群的吞吐量最高、等待时间最短、故障影响最小。如果你正准备入门 AI Infra或者已经在维护小规模训练集群、想搞明白大规模调度是怎么运作的这篇文章应该能帮你把调度器这个黑盒打开看看里面到底是怎么排班的。2. 调度器的本质它解决的从来不是排队而是分配决策很多人的第一反应是调度器不就是个先来先服务的队列吗任务来了排队有卡了就跑。这么想不能说全错但格局明显小了。2.1 先来先服务的问题出在哪如果一万张卡只跑一种任务——比如大家都是 8 卡训练、显存需求一模一样、跑的时间差不多——那先来先服务FCFS确实够用。可惜现实世界没有这么温柔。一个真实的训练集群里任务的规格五花八门有只跑数据预处理的单卡小任务占一张卡跑 20 分钟就结束有微调 7B 模型的任务要 4 张 A100跑两三个小时有预训练 70B 模型的大活一次要占 512 张卡一口气跑好几周还有一堆五花八门的 eval 任务、数据标注任务、baseline 复现任务资源需求千奇百怪。如果严格按照先来先服务会出现一个灾难性场景一个大任务进来了它要 512 张卡但当前集群只剩 500 张空卡。按照 FCFS 的规则它得排在队首等那 12 张卡空出来。但这 500 张卡闲着也是闲着后面的小任务全被它堵住一个都跑不了。整个集群的资源利用率可能跌到 50% 以下。这就像医院只有一个大手术室一台需要 512 平米的手术排在那里但医院只有 500 平米空着——为了等着补齐这 12 平米整个手术楼都空转。傻子都知道这不合理。2.2 调度器的真正决策空间所以调度器本质上干的是资源分配的多目标优化它要在几个互相打架的目标之间找平衡吞吐量优先单位时间内跑完的任务数尽量多集群整体利用率尽量高公平性优先每个团队、每个用户分到的资源配额符合预期别让一个大任务饿死所有人优先级保障紧急任务比如线上模型出问题要紧急回滚重训要能插队拓扑亲和性多卡任务需要高速通信卡最好分配在同一个节点或者同一个机架内跨机柜走以太网做同步那是灾难。不同的调度器本质是这四者的不同加权组合。比如训练场景下我们普遍更看重吞吐量和拓扑亲和性因为大模型训练任务动辄几百卡通信效率往往比绝对的公平更重要。这里补一句大白话解释拓扑亲和性一张 A100 的卡间通信走 NVLink带宽能到 600GB/s跨节点的卡间通信走 IB 网络也有 200Gb/s 左右但如果是跨机柜走普通以太网可能就剩 100Gb/s 不到了。你的任务如果被调度器散到八个不同机柜的机器上光通信损耗就能让训练速度掉一半。所以调度器在做分配的时候一定优先把同一个任务的卡放在物理上靠近的位置。2.3 有了 Kubernetes 为什么还要单独搞调度器可能有同学会问现在很多集群都用 Kubernetes 管理K8s 自带的 scheduler 不是也能排 Pod 吗为什么还要单独做一层训练调度器这个问题的答案恰好能帮我们理解训练调度器的特殊性。K8s 默认调度器解决的是微服务部署的问题——一堆无状态 Pod每个 Pod 要多少 CPU、多少内存调度器把它们分布到各个节点上保证负载均衡。但训练任务的资源模型远比这个复杂资源需求是二维的训练任务不仅要 CPU 和内存还要 GPU 显存、GPU 算力、卡间通信带宽K8s 原生的资源模型对这些抽象得很弱。任务是 gang 调度的一个大训练任务由几十个甚至几百个 worker 组成这些 worker 必须同时被调度到集群里才能开始跑。如果只调度了一半 worker另外一半等不到资源前面那半工作就白等了这叫 gang scheduling成组调度。K8s 默认调度器不关心这个它只保证每个 Pod 有地方跑至于这个 Pod 是不是跟它的兄弟 Pod 齐了它不管。任务有动态资源诉求训练过程中可能要用到梯度压缩、显存交换、弹性扩缩容这些需要调度器跟运行时深度配合K8s 的那套资源写好就不变的模型根本罩不住。所以在大规模 AI 训练集群里真正干活的往往是专用调度器——比如开源的 Volcano、Fairscale 那套思路、或者各家自研的调度系统而 K8s 只充当底层容器编排的工具。你如果去翻那些大厂的 AI Infra 分享会发现调度器这一层几乎都是自研的因为通用调度器在训练场景下根本不够用。3. 万卡调度器的核心机制排队、抢占、优先级、拓扑感知前面讲了调度器要做什么决策这一节我们拆开来看它具体怎么运作。我选四个最关键的机制展开因为理解了这四个调度器在你眼里就不再是黑盒了。3.1 队列模型与排队策略几乎所有训练集群的调度器都会把任务先塞进队列——注意不是一条队列而是一堆队列。正常的做法是按团队或者业务线划分多个队列每个队列有自己的配额quota。比如 A 团队租了 4000 张卡B 团队租了 3000 张卡C 团队 2000 张卡剩下 1000 张是共享资源池。每个团队内部的任务再用自己的子队列排队。这么做的好处有几个故障隔离A 团队有人提交了一个 buggy 任务占着资源不放最多也就影响 A 团队自己的队列不会把整个集群堵死。配额可控每个团队能用的资源上限是定死的不会出现一个团队无限囤卡的情况。共享池弹性共享资源池允许团队在高峰期借卡用用完了自动还回来提高整体利用率。排队策略也不只是 FCFS。实际工程里常用的策略有FIFO 优先级队列大部分任务按先来后到但允许高优先级任务跳到队首。DRFDominant Resource Fairness主导资源公平一种经典的公平调度算法核心思想是看每个任务对集群中最紧缺资源的占用比例谁的紧缺资源占用比例低谁优先。放在 GPU 集群里就是看谁要的卡相对少谁先跑防止一个大任务把所有人都堵死。基于 deadline 的调度有些任务有明确的完成时间要求比如明天要出评估报告调度器会按截止时间倒推排期。DRF 这个值得多说一句。它考虑的不是简单的任务个数而是资源份额。假设一个任务要 8 张卡另一个要 64 张卡集群总共 64 张卡。按 DRF前者主导资源份额是 8/6412.5%后者是 100%。显然前者优先。但它不是简单的小任务优先而是动态计算每个任务在所有维度GPU、内存、带宽上的最大需求占比取最小的那一个调度。3.2 抢占与优先级机制大任务和小任务的博弈队列模型解决的是谁先进队但现实里有个让人头疼的问题等资源的大任务和刚提交的小任务怎么调和最直白的方案是大任务优先因为它等的时间长。但这会让小任务无限期积压——一个要跑三天的 512 卡大任务排在那后面所有 1 卡小任务全等着三天内集群只在跑一个大任务其他人全被饿死。反过来如果小任务优先那大任务永远等不到足够的卡——每次都差几张卡被后来的小任务抢走。成熟的调度器会采用抢占preemption机制来折中。思路是这样的大任务进队列时如果资源不够先在队列里等着但那些跑着的小任务如果优先级低于这个大任务并且占用的卡正好挡了路调度器可以把小任务挂起preempt把卡腾出来给大任务大任务跑完小任务可以在 checkpoint 的基础上恢复。抢占机制的实现细节很讲究因为它涉及一个非常实际的问题训练任务被强行挂起代价到底有多大如果是单机小任务抢占几乎没代价重启就完事。但如果是几百卡的大模型训练任务中断意味着进度丢失、需要从最近 checkpoint 恢复重跑。所以工程上通常不会真的把小任务杀掉而是给任务打上可抢占和不可抢占的标签调度器会偏向等待大任务自然结束而不是强行抢占只有在非常紧急的情况下比如线上事故要紧急训练新模型才触发真抢占。这里有一个实操中常见的坑抢占比想象中频繁得多。在新模型训练的高峰期小任务经常被抢占如果代码没有做好 checkpoint 自动保存和恢复一个 eval 任务可能跑了几小时被告知被抢占需重新排队体验很差。所以好的实践是所有训练任务的代码里都强制做周期性 checkpoint并且支持从最新 checkpoint 恢复——这不仅是容错需求也是调度器可以放心抢占的前提。3.3 拓扑感知调度把通信代价算进分数里前文已经提到拓扑感知这一节展开说它的实现思路。当调度器决定把一个 64 卡的任务放到集群里时它不是随便挑 64 张空卡就完事而是要先计算候选分配方案的代价。代价函数一般包括几个维度节点内卡数同一个节点内能放的卡越多越好因为 NVLink 带宽最快机架内节点数同一个机架内的节点之间走的是叶交换机延迟较低跨机架/跨 Pod 通信尽量避免因为带宽受限与其他任务的干扰如果候选 GPU 所在节点上已经跑了一个同样需要大通信量的任务那么新的任务放上去可能互相争抢带宽这个也要算进代价。这本质是一个图嵌入和约束求解问题。常见的做法是把整个集群的物理拓扑抽象成一张图——节点、机架、聚合交换机、核心交换机每层链路的带宽和延迟都是边的属性然后把任务需要的卡数、通信模式全互联、分层 All-to-All、流水线并行也建模成图结构用类似图匹配的算法找到最优或近似最优的物理卡分配方案。实际工程里这一步通常会做预分配优化——比如每个大任务的首选分配位置列表在任务进队列时就算好一旦所需卡数空出来就立刻锁定不用每次都从头跑一遍规划算法。这里也提醒一个小白容易踩的坑调度器把卡分给你了不代表训练性能一定好。它只能保证拓扑最优但你代码里的通信模式如果写得很烂比如没做梯度累积、频繁同步、把 All-Reduce 当成循环调用照样会把 IB 网络打成瓶颈。调度器负责排班你负责干活两者缺一不可。3.4 动态状态管理节点故障、抢占、退避的联动万卡集群的另一个隐藏 Boss 是故障率。几万张卡每天都会有卡挂掉、节点失联、IB 链路闪断。调度器必须能感知这些变化并迅速做出反应。整个流程是这样的节点健康检查每台节点上的 agent 定期上报心跳和 GPU 状态温度、显存 ECC 错误、NVLink 健康度故障检测调度器如果一段时间没收到某个节点的心跳就把节点标记为 NotReady上面正在跑的任务会被重新调度任务恢复被故障打断的训练任务调度器会尝试在别的节点上重新拉起并从最近的 checkpoint 恢复训练节点驱逐如果某个节点反复出故障调度器会把它踢出资源池人工介入检修。这一套机制对工程师的影响非常直接你的训练任务可能不是因为你代码挂了而中断而是因为物理机挂了。所以代码层面一定要做容错设计——比如 PyTorch 的 TorchElastic 这类工具就是专门用来应对动态节点变化和故障恢复的。如果你在万卡集群上训练不做容错一个 512 卡、预计跑一周的任务基本上不可能顺利跑完——大概率中途被某个节点故障打断然后从零开始。4. 从排队到上卡一个训练任务在调度器里的完整旅程前面把调度器的核心机制拆开讲了但这还不够。我想带你走一遍一个训练任务从提交到跑起来的完整流程。这样你能看到一个真实的任务是怎么跟调度器交互的每一步的输入输出是什么。4.1 阶段一任务提交与画像Resource Profile你提交一个训练任务通常要告诉调度器这几个信息镜像地址、启动命令、环境变量需要的 GPU 卡数、CPU 核数、内存大小是否需要 RDMA/IB 网络需要多少带宽任务优先级、队列归属数据卷挂载信息。调度器拿到这些信息后做的第一件事是给任务画像——不仅记录资源的量还要对任务的形态做分类。因为不同形态的任务对调度策略的要求完全不同任务类型典型特征调度策略侧重单卡小任务1-4 卡时长 1 小时吞吐优先尽量塞到零散空闲卡上中型微调任务4-32 卡时长 1-10 小时优先拓扑亲和允许一定等待大模型预训练64-1024 卡时长数天到数周gang 调度等待可接受关键是启动后不被抢占数据预处理任务CPU 密集GPU 可选优先 CPU 资源充足的节点画像不是一次性的。调度器会在任务运行过程中持续监控实际资源使用率如果发现任务申请的 GPU 利用率极低比如跑一个数据加载卡瓶颈的脚本它甚至会把你的 QoS 等级降级后续调度更偏向压缩你的资源。反过来如果任务实际需求超过申请比如显存溢出被 OOM 杀调度器也会记录下次调度会优化分配策略。4.2 阶段二排队与配额校验任务画好像进入凭据校验阶段。这里卡住最多人的是配额quota不够。你可能在团队配额只有 32 卡的情况下提交了一个要 64 卡的任务调度器会直接拒绝并不会让它排队。配额校验通过后任务进入队列。这时候优先级起作用了。通常调度器会维护一个多级队列基本结构如下全局队列所有任务的入口团队队列按团队分组每个团队有自己的配额和优先级子队列团队内部按业务线/项目再分。调度的顺序是先从团队队列里取再看团队内部子队列的优先级同一个子队列内部再按照 FCFS 或者 DRF 排序。这里有个容易忽略的细节调度器计算配额时看的是正在使用的资源已经被排队的任务的资源需求量。也就是说你虽然提交了任务但它还在排队你这部分的配额就已经被预占了。如果你频繁提交任务又取消配额会被反复占住再释放影响整个团队的调度效率。实操上我见过很多团队因为先提交占坑再说的习惯导致队列里面全是僵尸任务调度器每次都得处理一堆无效的排队项。4.3 阶段三资源匹配与拓扑规划当队列里某个任务被选中调度器开始做资源匹配。这是最吃计算量的环节。以一个 128 卡、需要全互联通信All-to-All的任务为例调度器的算法大概是从集群的空闲节点列表里筛掉有故障的、正在维护的、GPU 型号不匹配的节点计算最优拓扑——优先在同一个节点内凑满 8 张卡然后在一个机架的两个节点间凑 16 卡再往上一层一层凑满 128 卡如果集群当前空闲卡只有 64 张那么 gang 调度会触发等待而不是部分分配因为 128 个 worker 缺一不可调度器给这个任务预留资源并启动一个定时器——如果在规定时间内比如 30 分钟仍凑不齐任务可能被降级为等待中但允许其他任务使用这些空卡或者直接提示资源不足。在集群规模较大的时候调度器通常会把资源预留和实际分配分开。预留的卡数不一定立刻物理锁定而是在分配那一刻才真正占用否则会白白浪费资源。但这个细节实现非常复杂需要调度器跟节点上的 agent 实时同步锁卡状态很多自研调度器的 bug 就出在这一层。4.4 阶段四启动、运行与弃权处理分配完成调度器把任务信息下发给各节点 agentagent 拉镜像、起容器、设置环境变量、挂载数据卷。注意到此为止调度器的调度工作还没完全结束。任务跑起来之后调度器会持续跟踪运行状态正常、失败、被抢占、失联心跳检测worker 进程是否活着如果某个 worker 挂了但容器还在调度器可能判定为训练卡死运行时长如果远超集群的平均训练时长可能触发提醒资源真实使用量持续监控如果 GPU 利用率过低可能被标记优化。任务结束后调度器做两件事回收资源、结算账单如果是内部计费系统。资源回收这里有个经典问题——显存泄漏的容器。有些训练代码跑完后显存没完全释放容器退出但 GPU 显存还挂着调度器如果不强制清理设备这块卡可能就废了。好的调度器会在任务终止时主动调用 GPU 清理逻辑而不是仅仅依赖容器销毁。5. 从单集群到联邦调度器横向扩展的玩法万卡集群的调度主要是解决一个集群内的问题。但现实里大公司很少把一万张卡放在一个机房——因为电力、散热、容灾都是物理瓶颈。更常见的布局是三个机房每个机房 3000-4000 张卡机房间走专线互联。这就出现了第二层调度问题跨集群调度。5.1 数据亲和性让跨集群调度变得棘手你可能会想跨集群调度不就是把任务分到三个集群去跑吗没那么简单。大模型训练的数据量动辄几个 TB如果数据只存在 A 集群的对象存储里你要在 B 集群跑任务光同步数据就可能要一两个小时。调度器在做跨集群决策时必须把数据的位置与传输成本也算进去。业界比较普遍的做法是数据分层缓存每个集群都有一份热数据缓存调度器优先把任务调度到数据已就绪的集群就近调度优先默认不跨集群调度只有在本集群资源不足时才考虑把任务溢出到其他集群数据预推送预测到某个任务可能被调度到远端集群提前把数据推过去减少等待时间。5.2 联邦调度的核心逻辑跨集群调度的架构通常是一个两级设计上层联邦调度器Global Scheduler感知所有集群的资源水位决定把任务分配到哪个集群下层本地调度器Local Scheduler在各自集群内做具体的拓扑规划与任务放置。联邦调度器只做粗粒度的资源预估不会管节点级别的事。它维护的是集群级别的资源视图——A 集群还剩多少卡、B 集群排队多不多、C 集群是否正在故障。本地调度器把资源水位上报给联邦调度器联邦调度器根据全局视图分配任务。这个两层架构有一个显而易见的痛点全局视图是延迟的。本地调度器每 30 秒上报一次状态联邦调度器拿到的可能是 30 秒前的数据。如果多个任务同时被分到资源已耗尽的集群本地调度器会面临很大的 reject 压力。这也是业界在尝试去中心化调度的原因——每个集群的调度器自治通过消息协商完成任务分配而不是依赖一个中心节点的全局视图。5.3 跨地域训练能跑但要做好大量实验准备跨集群调度的终极形态是跨地域训练——一个训练任务同时跑在两个城市的集群上通过专线互联做数据并行。理论上能给更大的模型、更多的数据并行度但实操中问题很多两地之间的网络延时即便走专线也有好几毫秒比机房内部网络的微秒级延迟差了上千倍千卡规模的任务频繁做梯度同步带宽根本扛不住任何一个机房的电力故障都会导致整个任务中断容错复杂度大幅上升。所以据我所知绝大多数团队的跨地域训练实际落地场景是数据和模型在不同地域但任务往往还是落在同一个集群跑只是数据并行复制到多地。真正把一个大训练任务拆到两个城市同时跑的基本都是实验性质或者只在非常特殊的 Model Parallel 场景下用。6. 可观测性没有监控数据的调度器等于在开盲盒聊到调度器实战就不能不提一个经常被忽略但其实极其关键的话题——可观测性。调度器做得再好如果看不到为什么这个任务没跑起来、集群资源到底去哪了你就永远只能靠猜。6.1 调度器的监控指标至少要看这几类我在帮团队搭训练平台的时候第一件事就是把调度器的监控面板立起来。核心指标大致分这么几类资源水位类集群总卡数、空闲卡数、各队列已用配额、共享池余量。这一层是总量体检让你一眼看清集群是不是满了、是不是有空闲卡被低效任务占了。调度效率类任务平均排队时长、任务被抢占次数、队列中 pending 任务数。如果发现平均排队时间超过 30 分钟往往不是资源不够而是调度策略有优化空间。任务生命周期类任务提交数、启动成功数、失败数、被抢占数。这个指标能帮你快速发现异常高峰——比如突然有一批任务因为镜像拉取失败全部失败调度器的状态再健康也没用。运行质量类GPU 平均利用率、显存平均利用率、IB 带宽利用率。这些指标反映的是调度下去的任务是不是真的在高效用卡。这几个维度要结合看。我看到过不少团队只盯着GPU 空闲率这一个指标拼命压任务排队时间结果每个任务都被调度到了零散的 GPU 上拓扑很差通信效率暴跌GPU 利用率反而得更低了。调度器的优化目标一定要拉通来看不能只看单点指标。6.2 调度器日志是排障的第一现场当用户问我的任务为什么还在排队的时候运维人员的第一动作不是去查代码而是去翻调度器的日志。调度器日志里通常有非常清晰的事件记录任务提交时间、进入的队列资源匹配检查的每个阶段是否通过未匹配到的原因例如可用节点不足、拓扑评分过差、配额不足被抢占的事件序列以及抢占原因节点故障导致任务被迁移的记录。我强烈建议做 AI Infra 的同学至少在调度器这一层把决策事件全部落日志并且按任务 ID 建索引。这样用户问问题的时候你能秒答你的任务在 14:32 提交14:35 因配额不足被拒绝14:40 重新提交后进入队列当前排在第二位。另外有一个经验把调度器的决策理由暴露给用户能减少 90% 的为什么我的任务不跑的工单。用户看到等待原因是节点组 A 剩余 GPU0自己就明白了不需要你解释。6.3 主动告警的关键姿势最后说告警。不是所有的异常都要告警告警配置的原则是只告警需要人干预的事件。比如队列资源耗尽这可能是常态不用告警比如任务排队超过 2 小时且一直没有调度成功需要告警比如某个节点在 10 分钟内连续触发 5 次任务失败需要告警比如可用的 GPU 卡数低于集群总卡数的 10%需要告警。告警配置太多会导致狼来了效应运维团队疲于处理最后谁都不当回事。好的告警配置是能够让你在集群出问题和收到告警之间建立强关联的——看到告警就等于出事了。7. 我踩过的几个坑和现在的处理习惯写了这么多原理和机制最后分享几个我在实际部署和运维训练调度器时真正踩过的坑。每一个都花过不少时间排查希望你能绕开。7.1 过度使用抢占导致小任务饿死刚开始搭调度系统的时候我的调度策略设定得很激进——高优先级的任务来了立刻抢占低优先级任务的卡。结果不到两周就收到反馈数据预处理任务的完成率掉到了 30% 以下。原因很简单数据预处理任务每次被抢占后重跑中间结果又没保存相当于白白浪费了之前的进度。更讽刺的是如果抢占时间恰好在任务快要完成的时候那损失比从头开始还大。后来我调整了策略数据预处理等可快速重启的任务允许被抢占但把 checkpooint 周期调短到 5 分钟以内超过 64 卡的大任务默认标记为不可抢占让它们跑完抢占只发生在紧急任务场景强制加白名单审批。现在的效果是小任务虽然偶尔还是会被抢但因为 checkpoint 频繁实际损失可接受大任务很少意外中断。7.2 调度器的资源预留白白浪费了几百张卡另一个大坑在资源预留策略上。早期我们的调度器在分配任务时一旦选定了候选节点就会把卡锁住等待任务启动。但任务启动要拉镜像、初始化环境经常要等 3-5 分钟如果镜像没缓存可能要 10 分钟以上才能起。在最坏情况下调度器已经分配但不实际使用的卡占了集群总卡数的 15%。这在大集群里是几百张卡的闲置浪费。后来我们改成了两阶段提交模式第一阶段pre-check只检查节点可用性、镜像是否缓存不实际锁卡第二阶段bind任务真正要启动时才把卡锁住。这样极大减少了卡已分配但还没跑任务的时间窗口。但代价是安全检查做得更严格——如果节点在你预检查通过后被其他任务占走了你必须在 Bind 阶段处理失败重试。7.3 只盯着 GPU 卡数忽略了显存维度调度器能不能准确调度前提是它能准确感知资源。早期我们的调度器只用 GPU 卡数作为唯一资源维度结果经常发生有卡但显存不够的尴尬局面。比如某个节点上有 8 张 40GB 显存的 A100但已经被碎片化地占掉了一些显存。一个新任务只申请 1 张卡却需要 60GB 显存——如果调度器只看卡数它会分配这一张卡任务一开始就 OOM。现在的做法是把显存也纳入调度维度资源匹配时同时校验卡数和显存可用量对经常申请大显存的任务比如 LoRA 微调、7B 以上模型推理提供显存独占还是显存共享的选项对于模型训练任务默认不允许显存共享因为训练会动态申请显存共享很容易触发 OOM。7.4 现在的处理习惯踩过这些坑之后我形成了一个处理调度问题的习惯分享出来可能对你有参考价值任何调度策略改动先做灰度。先在测试集群或者用一个团队的队列试两天看指标变化再全量推。调度器的指标面板要放在大屏幕上。每天看一眼调度效率、排队时间、GPU 利用率的趋势很多问题在变成事故之前就已经有苗头了。每次事故排查完都沉淀成一个 case。调度器相关的问题一次性排查常常需要好几个小时不沉淀的话下次遇到还是从头查。我们现在内部有一个调度疑难问题文档库排查效率提高了很多。跟训练框架团队保持沟通。调度器要和 PyTorch、Megatron 这些框架密切配合框架改了通信行为、显存管理方式调度器可能不知道这就会导致资源分配和实际需求错位。定期对齐很重要。8. 最后说说对调度器这个隐形老板的理解回到标题——调度器是训练场的隐形老板。这句话不是说它权力大而是说它决定了整个训练场的节奏与效率。一万张 GPU 摆在那里算力本身不是瓶颈怎么让这些算力被高效地利用起来才是真正的核心竞争力。这几年做 AI Infra 最大的体会是训练一个千亿参数模型代码层面的优化空间是有限的但调度层面的优化空间非常大。同样的集群规模调度策略调优前后资源利用率可以从 40% 提升到 80%这个差距比换更好的 GPU 还明显。所以如果你正在搭自己的训练集群不管规模是十张卡还是一万张卡建议从一开始就把调度这件事放在心上。哪怕你只是用开源组件也值得花时间理解它的调度模型、调参手段和监控指标。别等到队列堆积、资源混乱的时候再来补课——那时候你已经付出了太多时间成本。这一章下篇到这里差不多把调度器的排班逻辑讲透了。训练与调度是个越挖越深的话题后面如果有机会可以继续聊聊弹性训练、异构资源调度、以及调度算法与模型并行策略的联合优化。
返回列表