3. 任务调度基础:调度系统概念、调度策略与GPU资源抽象

3.1 调度系统在GPU集群中的位置与核心职责

在GPU集群中,调度系统是连接“用户提交的计算需求”与“底层GPU硬件资源”之间的核心控制平面。它的本质是一个多目标决策引擎:在任意时刻,集群中可能同时存在数百个来自不同团队、不同框架(PyTorch、TensorFlow、MindSpore)的训练或推理任务,而GPU资源(尤其是高端型号如A100/H800)在物理上是有限且异构的。调度系统需要决定:哪个任务先运行?运行在哪几台机器的哪几块GPU上?每块GPU分配多少显存和多少计算份额?

一个完整的调度决策通常包含三个子过程:资源上报与感知(Agent采集每张GPU的显存总量/已用量、SM占用率、温度等)、任务排队与策略选择(根据队列策略从等待队列中选出下一批任务)、资源分配与绑定(将选中的任务映射到具体的GPU设备上,并设置环境变量如 CUDA_VISIBLE_DEVICES)。

关键认知:调度系统不直接“搬运数据”或“执行计算”,它只做三件事——排序(决定谁先谁后)、分配(决定用哪块卡)、隔离(决定用多少资源)。这三件事的决策质量直接决定了集群的吞吐量、排队延迟和GPU利用率。
用户/上层平台 训练任务 · 推理服务 资源规格:8卡 · 每卡80GB 调度器(Scheduler) ① 策略排序(FIFO/公平/优先级) ② 资源匹配(显存/计算单元) ③ 设备绑定与启动 GPU资源池 节点1:A100×8 节点2:H800×8 提交请求 分配/绑定 调度策略 FIFO(先来先服务) 简单公平,但易队头阻塞 公平调度(Fair) 多队列间按权重共享 优先级调度 高优任务抢占/插队 GPU资源抽象 显存(HBM) 单位:GB / MiB,硬隔离 计算单元(SM/CUDA Core) 单位:核数 / 算力TFLOPS 可分割性差异 显存可切分,SM通常整卡独占 调度输出 环境变量注入 CUDA_VISIBLE_DEVICES=0,1,2,3 容器/进程启动 绑定GPU索引与显存上限 监控与反馈 利用率/显存水位 → 下一轮调度

3.2 三种核心调度策略:FIFO、公平调度与优先级

调度策略决定了等待队列中任务的出队顺序。不同策略在集群吞吐量、用户公平性和任务延迟之间做出不同取舍。

3.2.1 FIFO(先来先服务)

FIFO是最朴素的策略:任务按提交时间排序,先到先得。实现简单,完全公平(从时间维度看),且没有抢占开销。但它的致命弱点是队头阻塞——如果一个需要64卡的大任务排在队首,而集群当前只有32卡空闲,那么后面即使有多个只需4卡的小任务可以立即运行,也必须等待大任务凑齐资源。

3.2.2 公平调度(Fair Scheduling)

公平调度(典型实现如YARN的Capacity Scheduler、Kubernetes的Fair Sharing插件)将集群资源按队列/租户划分权重。例如:A团队权重60%,B团队权重40%。当A团队没有任务时,B团队可以借用A的配额(弹性);当A提交新任务时,B需要逐步让出(抢占或等待自然结束)。公平调度的核心是最小资源保障 + 弹性共享,避免单一团队饿死其他团队。

3.2.3 优先级调度

优先级调度允许任务携带优先级标签(如P0/P1/P2)。调度器总是优先选择高优先级任务,甚至允许高优任务抢占低优任务已占用的GPU。抢占有两种实现:冷抢占(直接杀死低优任务,释放资源)和温抢占(挂起低优任务,保存显存状态,待高优任务结束后恢复)。优先级调度能保证关键业务(如线上推理、紧急故障修复)的及时性,但需要配合配额限制,防止高优任务无限挤占导致低优任务饿死。

策略 核心目标 典型场景 主要缺陷
FIFO 时间公平、实现简单 单用户独占集群、任务同质 队头阻塞,大任务拖死小任务
公平调度 多租户资源保障与共享 多个团队共享集群 需要动态调整权重,有抢占开销
优先级 关键任务优先执行 混部场景(训练+推理) 低优任务可能饿死,需额外保护
生产建议:现代GPU集群调度器(如Volcano、Kueue)通常采用多层混合策略:先按优先级粗筛,再在相同优先级内使用公平调度,最后在队列内部使用FIFO。这样兼顾了紧急任务、租户公平和实现简单性。

3.3 GPU资源抽象:显存与计算单元

调度器必须理解GPU资源的可量化属性,才能做出合理的分配决策。GPU资源抽象主要分为两个维度:显存(Memory)和计算单元(Compute)。

3.3.1 显存抽象

显存是GPU上最直观、最容易被量化的资源。调度器通过驱动接口(如NVML)读取每张卡的总显存、已用显存和空闲显存。显存分配通常是硬隔离的——一旦分配给某个任务,其他任务无法使用,即使该任务当前并未充分利用。例如,一张A100 80GB的卡,如果任务A申请了40GB,那么剩余40GB可以分配给任务B;但如果任务A实际只用了20GB,那20GB的差额也无法被B使用(除非开启MIG或显存动态共享)。

3.3.2 计算单元抽象

计算单元(Streaming Multiprocessor,SM)是GPU执行计算的核心硬件。与显存不同,计算单元通常不支持细粒度切分。在传统模式下,一张GPU卡要么整卡分配给一个任务,要么通过MIG(Multi-Instance GPU)技术切分为若干实例(如A100可切分为1个40GB+2个20GB的实例),每个实例拥有独立的SM和显存带宽。但在大多数集群调度场景中,计算单元被抽象为“整卡”或“MIG切片”,而不是“SM数量”。

# 查看GPU资源抽象信息的典型命令(NVIDIA驱动层)
nvidia-smi --query-gpu=index,memory.total,memory.used,utilization.gpu \
           --format=csv

# 输出示例
# index, memory.total, memory.used, utilization.gpu
# 0, 81920 MiB, 32768 MiB, 45%
# 1, 81920 MiB, 81920 MiB, 100%
# 2, 81920 MiB, 0 MiB, 0%

调度器在分配时,需要同时满足显存约束和计算单元约束。例如,一个任务声明需要“4卡×40GB显存”,调度器必须找到4张空闲显存≥40GB的卡,且这4张卡的计算单元未被其他任务独占。如果集群中只有2张卡满足显存条件,但它们的SM已被MIG切分占用,则任务仍需等待。

3.4 案例:一个典型调度决策的完整过程

假设某集群有2台物理节点,每台节点8张A100 80GB GPU。当前状态如下:

  • 节点1:GPU0-3被任务X(4卡训练)占用,GPU4-7空闲
  • 节点2:GPU0-1被任务Y(2卡推理)占用,GPU2-7空闲

此时新提交两个任务:任务P(优先级P0,申请8卡×80GB,用于紧急故障恢复训练)和任务Q(优先级P1,申请4卡×40GB,用于常规实验)。调度器执行以下步骤:

  1. 资源过滤:任务P需要8卡且每卡80GB,但节点1只有4卡空闲,节点2有6卡空闲,均不满足单节点8卡要求。若调度器支持跨节点(需高速互联如NVLink+IB),则可将节点1的4卡+节点2的4卡组合给P;若不支持跨节点,P只能等待。
  2. 策略排序:假设支持跨节点,P优先级高于Q,P先被调度。调度器为P分配节点1的GPU4-7和节点2的GPU2-5。
  3. 资源分配:剩余资源为节点2的GPU6-7(2卡×80GB)。任务Q申请4卡×40GB,但剩余卡数不足4张,因此Q进入等待队列。
  4. 环境注入:调度器通知节点1和节点2的Agent,在P的容器中设置 CUDA_VISIBLE_DEVICES=4,5,6,7(节点1)和 CUDA_VISIBLE_DEVICES=2,3,4,5(节点2),并启动分布式训练框架(如torchrun)。
常见误区:许多初学者认为“显存够用就能调度”。实际上,计算单元的独占性往往才是真正的瓶颈。例如,一张A100 80GB的卡,显存只用了10GB,但SM利用率已达95%。此时如果调度器仅凭显存空闲就分配新任务,会导致两个任务争抢SM,造成严重的性能抖动。生产环境必须同时考虑显存水位和SM利用率,甚至要关注显存带宽(HBM带宽)是否饱和。

3.5 误区与复盘:调度策略选择中的典型教训

误区一:盲目追求“公平”而忽略业务差异。某公司内部统一使用公平调度,所有团队权重相同。结果导致线上推理任务(延迟敏感)与离线训练任务(吞吐优先)混部时,推理P99延迟从5ms飙升至200ms。复盘发现,公平调度让推理任务和训练任务各分50%资源,但推理任务需要的是低延迟而非高吞吐。修正方案:为推理任务设置独立的高优先级队列,并配置资源预留(最低保障80%),训练任务使用弹性剩余资源。

误区二:将显存作为唯一资源维度。某团队在调度器中只配置了显存限制,没有考虑SM数量。结果两个小任务被分配到同一张卡上,各自申请20GB显存(共40GB,小于80GB),但两个任务都是计算密集型(各自需要50% SM)。实际运行中,两个任务互相干扰,训练速度比独占时下降70%。复盘结论:必须将计算单元(SM/MIG切片)作为独立的资源维度参与调度,不能只靠显存判断。

误区三:FIFO在小集群中“看似够用”。一个4卡GPU服务器,团队5人,每人偶尔提交单卡任务。初期使用FIFO没有明显问题。但当某人提交了一个4卡全占的大任务后,其他4人的小任务全部排队等待数小时。复盘发现:FIFO缺乏任务时长预估和资源抢占机制。改进为:限制单任务最大占用时长,超过后自动挂起;同时允许小任务在预留资源上运行。

核心复盘结论:调度策略没有绝对的“最优”,只有“最适合”。选择策略前必须明确集群的业务混合度(训练/推理比例)、用户规模(单租户/多租户)、任务时长分布(分钟级/小时级/天级)。建议先以公平调度为基础,再叠加优先级队列,最后用FIFO处理同优先级内部排序。同时,资源抽象必须同时包含显存和计算单元,并定期监控实际利用率来校准调度参数。