ARTICLE DETAIL

资讯详情

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

大模型训练隐形老板:GPU调度器核心职责与选型避坑实战

大模型训练隐形老板:GPU调度器核心职责与选型避坑实战 走进一万张卡的训练机房第一眼看过去是密集的机柜、嗡嗡呼啸的风扇、以及上百台交换机之间跳动的光纤。但对大模型训练来说真正决定效率的核心并不是那堆闪闪发光的 GPU 卡而是落在调度配置里的一行行规则谁先跑、谁排队、谁占多少卡、挂了谁来顶。这背后的执行者就是训练场的隐形老板——调度器。打一个大家都能听懂的比方调度器就像食堂里那个打饭阿姨GPU 是热菜模型训练任务是饥肠辘辘的干饭人。菜做得再好如果阿姨不懂排号、叫号、判断谁该多盛一勺食堂照样乱成一锅粥。到了万卡规模这位“阿姨”不仅得会排班还得处理食材断供、锅灶起火、有人插队等一切突发状况。这篇文章就围绕“一万张 GPU 怎么排班”这个话题展开聊聊调度器在大规模训练场里的核心职责、调度算法怎么选型、多团队共享集群时怎么端平一碗水、我这些年在一线踩过的坑以及一份看完就能上手的排查清单。不管你是正在搭 GPU 集群的基础设施工程师还是被“任务老是卡在 Pending”折磨的训练同学这篇内容应该都能帮你少走不少弯路。1. 调度器到底管了什么它凭什么当“隐形老板”1.1 模型训练里调度器被严重低估了很多刚接触大模型训练的人有个误区觉得训练跑得慢要么是模型代码写得不行要么是 GPU 卡不够好。直到某天模型训练任务一个接一个卡在排队阶段GPU 空闲一大片才发现真正卡脖子的往往是调度系统。调度器做的事情本质上是“资源分配决策”。它知道集群里有多少张 GPU、每张卡的健康状态、每个节点上有多少剩余显存它也清楚每个训练任务需要几卡、多大显存、需要跑多久、属于哪个团队。然后它要根据这些信息决定下一秒让哪个任务上卡、哪些任务继续等着。在万卡规模下人工盯是绝对不可能的。一台一台去查 GPU 剩余量、再去估该给哪个任务分配卡光这个动作就得花几个小时更别提训练任务经常会失败重启、节点偶尔会掉线。调度器的价值就是把这些所有“该让谁上”的决策规则化、自动化用代码把资源裁决做掉。我经常给团队新人打一个比方调度器不直接产生算力但它决定了算力能不能被用起来。它不是训练场里的发动机而是变速箱——没有它发动机再猛也跑不出速度。1.2 调度器的四项核心职责注册、排队、拉起、自愈调度器表面上只是个“排队系统”实际运作起来要干的活儿比想象中多得多。我从实际运维的角度拆解一下它至少承担四个方面职责资源注册与目录管理。每张 GPU 都像员工一样要有“档案”。调度器需要维护一张集群资源表记录每个节点的 GPU 型号、显存大小、驱动版本、当前剩余卡数、健康状态。卡坏了要能自动标红下线新扩容的节点要能自动发现并纳入调度池。这套机制相当于 HR 手里那张花名册如果不准后续所有决策都是瞎蒙。任务排队与匹配分配。训练任务提交之后调度器要根据任务的资源需求几张卡、多少显存、约束条件必须落在有某类 GPU 的节点上、优先级哪些任务可以插队来做匹配。所谓“排班”这里是最核心的动作。生命周期管理。任务分配只是开始调度器还要负责把任务真正拉起来、运行中监控它的健康状态、结束后回收资源。万卡训练中容器被 kill、节点重启、驱动崩掉都是日常事件调度器要保证任务失败后能重新排队、重新调度而不是直接变成没人管的僵尸进程。故障自愈与故障域隔离。某个节点上的 GPU 温度一高训练就会显著变慢甚至报错。调度器发现节点异常后要能自动把所有任务迁移走把故障节点隔离出调度池防止一颗“老鼠屎”拖垮整锅汤。在故障域上也要有讲究比如一个训练任务最好别全放在同一个机架或者同一个交换机下否则一次断电、一次机房网络抖动整个任务全军覆没。2. 调度策略的核心机制排队、分配与抢占背后的门道2.1 两种最常见的分配策略binpack 和 spread调度器最常见的两种分配策略业内叫 binpack 和 spread。听名字可能有点懵我用搬家装货来展开。binpack 是“能塞就塞”优先把任务调度到已经部分占用的节点上尽量把整机塞满。这样做的好处是容易省出完整空闲的机器。比如一个集群有 20 个节点、每节点 8 卡100 个任务各要 1 卡。如果全部用 binpack 策略调度器会把任务往现有节点上不停堆最后可能只需要 13 个节点左右就装完剩下 7 个节点完全空闲。这些空闲节点可以关机省电或者留给需要整机 8 卡的大任务。spread 则是“均匀铺开”把任务打散到尽可能多的节点上。好处是单节点故障时影响面比较小不会因为一个节点挂了导致很多任务同时失败坏处是碎片化比较明显大任务来了可能找不到连续的空闲卡位。策略优点缺点典型适用场景binpack资源利用率高能腾出整机空闲单点故障影响面大成本敏感、卡特别贵的集群spread故障影响面小负载均衡碎片多凑不齐大任务稳定性优先、多租户共享集群实践里怎么选我的经验是如果集群里有大量需要 1 卡、2 卡的小任务同时也有 8 卡整机的大任务那最好做成混合策略——小任务用 binpack 优先填满某些节点大任务专门预约空闲整机。调度器的策略配得好不好直接体现在月底的电费和任务平均等待时间上。2.2 多团队共享集群队列、优先级和抢占怎么端水万卡集群很少有人是独占使用的通常好几个算法团队共用。这时候调度器要面对一个极其现实的问题A 团队在跑一个 512 卡的预训练B 团队急着上线一个 64 卡的微调任务C 团队只想调试代码要用 2 卡。该先给谁这就是调度器里的队列和优先级机制发挥作用的地方。可以把排队理解成食堂的窗口制度。FIFO先来先服务就是只有一个窗口排在前面的先打饭Fair Scheduler公平调度就是多开几个窗口保证每个团队都有机会打饭Capacity Scheduler容量调度则是给每个团队固定分配一个窗口的份额比如 A 团队最多用 50% 的资源B 团队最多用 30%剩下的归 C。而抢占机制就是“VIP 来了普通窗口要给 VIP 挪位置”。比如高优任务提交后调度器发现预留配额不够可以强制把低优先级任务的资源回收等低优任务重新排队。这个过程听起来很爽但实际操作中要非常小心。如果抢占过于激进可能导致低优任务一直训练不完反复被掐断、反复重新排队整个集群有效吞吐反而下降。我推荐一个土办法给每个任务设置最长等待时间和最小运行时间。低优任务一旦运行超过某个时间阈值就不再被抢占高优任务如果等太久调度器可以选择弹性扩容或者提醒管理员人工介入。规则一定要先跟业务团队对齐否则“调度器乱杀任务”的投诉会淹没你。另外提醒一句任务编排调度和资源调度是两码事。像海豚调度器DolphinScheduler这类工具解决的是“某个工作流里 A 任务跑完再跑 B 任务”的依赖编排而 GPU 调度器解决的是“这么多任务谁先上卡、上几张卡”。前者管流程后者管资源二者很容易混为一谈实际部署时是两套系统配合使用。2.3 显存怎么分配训练和推理需求完全不一样调度器分配 GPU 时不能只看“几张卡”还要看“每张卡上的显存够不够”。这也是大家常讨论的一个点GPU 显存容量到底是测算训练还是推理用的答案是训练和推理都要测但侧重点不一样。训练时显存不仅要装模型参数还要装梯度、优化器状态、激活值。Adam 优化器一开额外显存开销可能比模型本身还大。这也是为什么 7B 模型用 FP16 推理可能一张 24G 卡就够但训一次全参数微调怎么也得 4 卡甚至 8 卡 A100每卡 80G才能塞下。推理时显存需求相对小主要装权重和前向激活值但有个新问题推理请求是动态的并发请求一多显存占用会像商场客流一样突然暴涨。如果调度器给推理服务分配的显存太满一个峰值请求就能把卡压爆。分配显存的另一个隐藏坑是“显存碎片”。比如一张 80G 的卡已经跑了几个小任务占掉了 10G、20G、30G 的零散空间剩余可用显存是 20G但它们在显存空间上并不连续。有些训练框架申请显存时要一大块连续空间此时调度器明明显示“还剩 20G”任务却报显存不足。集群里的显存碎片一多浪费会比想象中严重很多需要靠定期整理碎片或者干脆采用更激进的 binpack 策略把小任务聚到特定节点上。2.4 为什么 GPU 满载了任务还在排队聊聊背压我经常被训练团队问一个问题“集群 GPU 明明已经满载了为什么我的任务还在排队是不是调度器坏了”绝大多数情况下调度器没坏问题出在“资源配额已满”和“背压机制”上。调度器本质上是一个多生产者多消费者的系统。为了让集群不因为任务太多而崩溃调度器必须做限流——这和我每天早高峰开车的道理一样高速路口如果让所有车同时冲进去结果不是跑得快而是全线堵死。调度器的背压机制就是控制单位时间内能进入集群运行的任务数量宁可让一部分任务在外面排队也不能让太多任务同时在集群里互相抢资源最后谁都跑不动。所以一个任务处于 Pending排队状态时可能是三种情况集群真的没有足够的空闲资源有足够资源但团队配额已经用尽系统在做背压限流防止恶意突发任务拖垮集群。遇到任务排队第一步先去看调度器的队列深度和等待原因而不是盲目重启任务或者找运维“加卡”。很多线上事故都是因为有人反复手动把卡从别的任务里抠出来打乱了调度器的全局安排。3. 万卡集群怎么选调度器从开源方案到落地实战3.1 主流调度器横向对比Kubernetes、Volcano、SLURM调度器的选型是万卡集群最核心也最纠结的决策之一。我把主流的几套方案放在一起聊聊不吹不黑就当是给还没有踩坑的同学一份参考。Kubernetes 原生调度器如果你已经是云原生架构用容器跑训练那 K8s 原生调度器是最容易上手的方案。它简单、稳定、社区生态大但默认调度逻辑比较基础对 GPU 这种特殊资源支持不够精细。比如它默认把 GPU 当作“整数资源”来分配一张卡不能拆成两半用也不擅长处理大批量训练任务的批量调度。Volcano这是 K8s 生态里专门做高性能批量调度的扩展组件底层还是 K8s但补充了 K8s 原生调度器缺乏的很多能力比如 Gang Scheduling任务组排队和统一调度、队列管理、优先级抢占、资源配额、拓扑约束等。对跑大模型训练的场景来说Volcano 基本是必选项。SLURM这是高性能计算领域的老牌调度器很多老牌超算中心和传统 HPC 团队都在用。它非常稳定、调度效率高但和云原生、容器生态的整合不够好灵活性稍弱。如果你团队主战场是传统 HPC 脚本而不是 Docker 容器SLURM 依然是可靠选择。调度器优势劣势推荐场景Kubernetes 原生调度云原生生态、简单易用GPU 资源调度能力弱小规模 GPU 集群、推理服务Volcano支持批量任务、Gang、队列、抢占需要额外搭建和调优大规模训练集群、大模型训练SLURM稳定、HPC 生态成熟容器支持弱、弹性较差传统超算、脚本式科学计算以开源社区的活跃度和大模型训练的实际情况来看当前比较主流的选择是“K8s Volcano”组合再根据自己的情况做一些插件开发比如实现自定义的拓扑感知调度策略。3.2 弹性配额与分时复用一张卡一天可以干好几份活万卡集群买回来是巨大成本如果利用率拉不上去老板看账单的脸色会很难看。提高利用率的一个常见做法就是弹性配额和分时复用。弹性配额的意思是团队的资源配额并不是一条死线。比如 A 团队白天在线推理业务繁忙需要 60% 的卡到了晚上推理流量下降就可以把配额临时让给跑离线训练的 B 团队。调度器可以根据时间窗口或者实时的资源水位自动调整配额让同一批 GPU 在一天之内被不同用途的任务复用。分时复用则是把一张卡按时间片或者按显存颗粒切分。比如一张 80G 的卡白天跑四个 20G 的在线推理实例晚上流量降下来就把其中三个实例缩掉让出 60G 给夜间批量训练。这里的关键是调度器要支持“任务收缩”和“资源调整”的能力能在运行中动态修改任务占用的显存和卡数。弹性配额最大的价值是把 GPU 平均利用率从 40% 拉到 70% 以上。我见过不少团队一开始调度配置只会写死“谁多少张卡”后来改成弹性配额之后同样的卡数能多跑接近一倍的训练量。调度器配得好不好月底看账单就知道区别了。3.3 拓扑敏感调度卡放哪里直接决定训练快慢多机多卡训练里通信开销常常被低估。以 AllReduce 为例N 张卡同步梯度通信量随卡数增加基本是平方级增长。如果任务里的卡被调度器乱丢到不同机架、不同交换机下面跨机通信要走好几次网络转发训练速度可能直接掉一半甚至更多。拓扑敏感调度就是为了解决这个问题。调度器在分配任务时不仅看“有没有卡”还看“这些卡之间的物理距离有多近”。最理想的部署是同一个训练作业的卡尽量落在同一个节点上其次是同一机架、同一 NVLink 域内。不同节点之间能走高速互联通道就尽量别走普通网络。这就像请客吃饭大家坐在同一张桌子上聊天肯定比隔着一栋楼喊话效率高。如果你的训练任务用了模型并行通信频率更高、延时更敏感那调度器对拓扑的要求就更高。有意思的是MoE混合专家这类模型结构反倒可以故意把专家分散到不同节点上因为专家并行天然就是跨节点通信调度策略又是另一套逻辑。所以我给基建团队的建议是不要只做一套拓扑策略要能根据训练框架的类型灵活切换。3.4 没有监控就没有调度可观察性是调度的生命线调度器再智能如果看不到集群实时状态本质上也是“盲人开车”。可观察性是调度系统能不能真正落地的生命线。我一般要求监控体系至少覆盖四个层面物理层监控每张卡的 GPU 温度、显存温度、风扇转速、功耗、时钟频率。用 nvidia-smi 和 DCGM 一类的工具持续采集异常指标能直接触发告警。调度器层监控任务 Pending 数量、队列深度、调度成功/失败次数、任务等待时间分布。这里能看到调度器本身是否健康有没有任务积压。业务层监控单任务的训练吞吐量比如每秒多少样本、梯度同步耗时、数据加载耗时。调度问题会间接体现在这些指标上值得算法团队也关注。资源利用率监控集群总体 GPU 利用率、显存利用率、特定节点的空闲率。这是调优调度策略最原始的依据没有数据寸步难行。只有把监控搭起来你才有底气做调度策略调优。否则你改一个参数到底变好还是变坏全靠猜。4. 实操避坑我在一线遇到过的调度器翻车现场4.1 翻车现场一任务在排队GPU 却空闲一半这是我维护 GPU 集群时遇到最多的一种诡异情况打开监控面板明明集群还有几百张空闲卡新提交的任务却一直卡在 Pending怎么也调度不上去。排查这种问题我会按下面这个顺序来第一步看团队配额。挂载在任务上的配额是不是已经用满了配额用尽的情况下哪怕集群真的有很多空闲卡任务也进不去。这是最常见也最容易被忽略的原因。第二步看节点标签和污点。K8s 里如果节点上有 taints污点或者没有匹配的 nodeSelector任务会被调度器直接过滤掉导致看起来“有卡却上不去”。很多运维加了污点忘记删或者标签写错就会造成这种假性空闲。第三步看显存碎片。用 GPU 监控看看空闲卡是不是都被小任务占了一部分显存如果都是“剩 10G、剩 15G”这种零散容量而你的任务要求 32G 显存那调度器在显存匹配上就会失败任务永远排不上。这个案例给我的教训是调度问题不一定是调度器本身的问题很可能是底下资源状态、标签配置、配额策略等外围因素的综合结果。排查的时候要有耐心从外到内一层层剥开。4.2 翻车现场二一次“GPU 卡死”引发的连锁反应大模型训练长时间跑GPU 偶尔会“挂掉”表现为某个算子在卡上执行不动训练进程 hung 住既不报错也不退出。这个时候如果调度器没有超时驱逐机制任务会一直占着卡其他任务只能干等。有一次我们在跑一个 256 卡的任务中途有一张卡触发了 GPU Crash Dump驱动直接把上下文丢了。没有容错机制的调度器完全没有反应训练作业挂在那边整整十二个小时浪费的算力换算成钱足够吃好几顿大餐了。后来我们加了两道保险一道是容器层面的健康检查livenessProbe。每 30 秒检测一次训练进程的日志心跳超过 3 分钟没有新输出就判定为死锁自动杀掉容器让任务重新排队。另一道是调度器层面的故障驱逐。调度器定期检查节点上的 GPU 状态如果发现温度异常、ECO 报错或者驱动丢失就直接把该节点标记为不可调度并将上面的任务驱逐到其他健康节点。这套机制上线之后再遇到 GPU 卡死集群基本能在 5 分钟内自动恢复不再需要半夜被电话叫起来手动处理。调度器的价值这一刻体现得特别实在。4.3 我常用的五条排障命令和日常巡检清单最后分享几个我在排障时最高频使用的命令和巡检动作对正在搭集群的同学应该能直接派上用场kubectl get nodes -L gpu-type一目了然看到集群所有节点的 GPU 类型和状态检查是否有节点被误标为不可调度。kubectl describe pod pod-name查看任务调度事件里面会明确写出“0/8 nodes available”或是“insufficient memory”这类原因这是定位 Pending 的第一入口。nvidia-smi -pm 1打开 GPU 持久化模式减少运行过程中驱动初始化带来的性能抖动排查卡顿问题时也会用到。nvidia-smi dmon持续监控每张卡的利用率、显存、温度、功耗变化适合定位“某张卡是不是偷懒了”这类问题。journalctl -u kubelet | tail -200看节点上 kubelet 的日志调度器下发任务后启动失败大多数报错都能在这里看到。日常巡检我维持在每周一次的频率重点看四张图集群 GPU 平均利用率、Pending 任务数曲线、节点故障率、显存碎片率。只要这四条线不出大问题调度系统基本是稳的。等哪天真出问题再顺着监控一层层往深处查。5. 高频问题速查表与新手入门建议5.1 高频问题速查表问题现象可能原因解决思路任务一直 Pending集群却有大量空闲卡团队配额用尽、节点标签/污点不匹配、显存碎片检查配额、节点标签、显存空闲分布显存明明够任务却报显存不足显存碎片化连续大块显存不足整理碎片考虑 binpack 聚拢小任务节点 GPU 卡死任务长时间无输出驱动故障、温度过高、算子死锁配置健康检查和调度器自动驱逐多任务同时训练整机利用率很低拓扑不匹配跨节点通信开销太大启用拓扑感知调度尽量整机放置低优先任务总被抢占训练无法收敛抢占策略太激进设置最长等待时间、最小运行时间阈值GPU Crash Dump 触发训练中断驱动崩溃或硬件异常检查驱动日志、重启设备必要时换卡5.2 新手入门从哪开始单机到万卡的进化路径很多人一上来就想搭万卡集群我其实不大建议。调度的复杂度是随规模非线性上升的你在 4 张卡上遇到的调度问题和 10000 张卡上遇到的调度问题完全是两个物种。我给新同学的路径建议是第一步先在单机多卡上理解显存分配和并行模式搞清楚 DDP分布式数据并行、FSDP全分片数据并行在显存占用上的区别。不理解模型本身怎么吃显存你就没法理解调度器为什么要对显存做精细管理。第二步搭一个几台机器的小型 K8s 集群部署 Volcano把队列、优先级、配额这几个核心概念在小规模上摸透。踩过几次坑之后再去碰大规模就不会手足无措。第三步在完成前两步的基础上再去调研万卡集群的拓扑感知调度、故障自愈、弹性配额这些高级话题。这就像练武功先扎马步再学招式调度器的基本功是 Linux、容器、网络和分布式系统这四样缺一不可。写在最后的几点体会做 AI Infra 这几年我越来越觉得调度器是个不太起眼但极其重要的角色。它不像模型结构那样动辄刷榜也不像 GPU 集群那样肉眼可见地闪闪发光但真正把集群利用率从 40% 拉到 70% 以上靠的恰恰是这层看不见的规则。我个人的一个建议是很多团队的调度配置停在“能用”的层面从没认真优化过。我建议每周花半小时看一眼集群利用率曲线哪里常年空闲、哪里总是排队调优方向就在那张图里。调度器排的不是代码是钱——一万张 GPU 每天的成本非常可观调度做得好不好月底账单会告诉你答案。最后再分享一个小技巧每次调整调度策略时不要一次性改多个参数改一个、观察一天、记录数据再改下一个。调度器的问题很多是参数之间互相影响你要能分清是哪个变量导致的收益这样才算真的在调优而不是在碰运气。
返回列表