跳转到内容

Gang Scheduling、抢占与回填

多团队共享一个 GPU 集群时,调度器要回答三个永恒的问题:大作业怎么整组进(gang)、被抢了怎么办(preemption)、空闲碎片怎么填(backfill)。这三个机制的组合决定集群的利用率与公平性——利用率 40% 和 80% 的集群,同样是 1000 卡,产出差一倍。

训练作业的天然属性是 all-or-nothing:64 卡的作业来了一半卡位,启动也没用(凑不齐就死锁,见训练容错)。

调度方式行为问题
逐 Pod(K8s 默认)有卡就起死锁:两个大作业各拿一半,互相等
Gang(整组)凑齐全部才启动,否则整组等大作业可能长期等不到

gang 解决死锁,但引入新问题:大作业的等待时间——64 卡的作业要等 64 卡同时空闲,碎片化越严重等得越久。这就需要回填。

回填:大作业排队等待时,小作业填进碎片空闲里——只要不推迟大作业的预期启动时间(EASY backfill:预留大作业需要的资源):

时间 → 大作业(64卡,等待中,预留从 T0 开始的资源)
小作业(4卡)███ 填进碎片(在 T0 之前结束)
小作业(8卡)████ 填进另一段碎片

三个效果:

  • 碎片利用率:没有回填,碎片空转;有回填,碎片被小作业填满
  • 大作业不受损:EASY 回填的约束是"不推迟大作业的启动"——小作业填的是大作业不需要的时空
  • 公平的自动实现:大作业优先(预留),小作业受益(填空),不牺牲任何一方

Slurm 的 backfill 原生支持(schedtype=backfill);K8s 靠 Volcano/Kueue。回填是"利用率免费提升"的核心机制——生产集群不开 backfill,利用率常低 20–30%。

抢占:高优先级作业来了,低优先级的正在跑——抢不抢、抢谁、怎么恢复:

策略行为适用
无抢占严格先来后到单一团队、纯批处理
优先级抢占高优抢低优生产/实验分级的标准
配额内不抢超配额才可被抢多租户公平(见下一章)

抢占的代价被低估了:被抢的训练作业不是"暂停",是"作废回检查点"——GPU 上没有真正的 suspend(显存必须释放),被抢 = 杀掉 + 从检查点恢复。每次抢占的真实成本 = 恢复时间 + 丢失的进度(见容错的账)。

所以生产集群的抢占设计要克制:

  • 分级的优先级(生产 > 预发 > 实验),只在跨级时抢
  • 抢占的粒度是整作业(不能抢半个训练)
  • 配额保护:团队的配额内不可被抢(超出配额的部分可被抢)——公平与效率的平衡点

三个机制对集群利用率的贡献,算一笔账(1000 卡、平均利用率):

配置典型利用率说明
无 gang(死锁频发)30–50%死锁占坑
gang + 无回填50–70%碎片空转
gang + backfill + 分级抢占80–90%生产标准
理论上限~95%维护与切换开销

从 50% 到 85% 的利用率提升,等于免费的 70% 算力——这比任何内核优化的绝对收益都大(见效率与成本卷)。调度策略是"最便宜的性能优化"。

  1. gang 调度开启(Volcano PodGroup / Slurm 原生)——死锁是第一杀手
  2. backfill 开启(Slurm: SchedulerType=sched/backfill)——碎片的免费利用率
  3. 优先级分级(生产/预发/实验三级)+ 配额保护——抢占只在跨级
  4. 作业的资源声明准确(CPU/内存也声明,避免抢占与碎片)
  5. 监控:队列长度、等待时间、碎片率、各团队的实际使用 vs 配额
  • Gang 调度解决逐 Pod 调度的死锁:整组进或整组等,是训练集群必选项。
  • Backfill 填碎片且不推迟大作业(EASY 策略):生产集群不开 backfill 利用率低 20–30%。
  • 抢占的真实成本 = 杀掉 + 检查点恢复(GPU 无 suspend);设计要克制:分级 + 配额保护。
  • gang + backfill + 分级抢占的组合让利用率从 50% 到 85%——等于免费 70% 算力,比内核优化更值钱。
  • 监控队列、等待、碎片率与配额使用,调度策略的调优数据从监控来。