GPU资源调度基础:调度器类型、调度策略、资源分配模型

GPU资源调度是连接“用户提交的计算任务”与“底层硬件算力”之间的核心枢纽。与CPU调度主要关注时间片轮转不同,GPU调度必须同时处理计算资源(SM/CUDA Core)、显存带宽、PCIe/NVLink传输以及多租户隔离等多维约束。理解调度器类型、调度策略与资源分配模型,是后续进行性能调优的前提。

一、核心原理:GPU调度的三层视角

GPU资源调度并非单一模块,而是从硬件到软件分层协作的结果。我们可以将其拆解为三个层次:

  • 硬件层(GPU内部调度器):GPU硬件自带的Work Scheduler(工作调度器)负责将线程块(Thread Block / CTA)分发到SM上。它遵循“先到先服务+负载均衡”的硬件逻辑,每个SM可同时驻留多个线程块,直到资源(寄存器、共享内存)耗尽。
  • 驱动/运行时层(CUDA Runtime API):负责将kernel启动参数、显存分配请求转化为硬件指令。此层决定stream(流)的优先级、事件同步以及默认的“广度优先”或“深度优先”调度顺序。
  • 集群管理层(Kubernetes + Device Plugin / Slurm + GPU插件):这是数据中心最关注的层。它决定“哪个容器/任务获得哪块GPU”,以及“一块GPU是否被多个任务共享”。
关键认知:上层调度器(如K8s)只负责“分配哪块物理GPU”,而真正微观的SM级调度由GPU硬件完成。因此,调优必须同时关注“宏观分配”与“微观占用”。
GPU资源调度分层与分配模型 ① 集群管理层(宏观分配) Kubernetes + Device Plugin 调度粒度:整卡 / MIG / 时间切片 Slurm + GPU 插件 调度粒度:整卡 / 任务独占 共享策略:时间切片 / MIG / 多进程服务(MPS) 决定“谁可见GPU”与“隔离级别” ② 驱动 / CUDA Runtime 层(上下文与流) Stream 调度 默认流(Default) / 多流并发 CUDA Context 管理 显存分配 / Kernel 启动参数 优先级与事件同步 cudaStreamQuery / cudaEvent ③ 硬件层(GPU 内部微观调度) GigaThread 引擎 全局线程块分发 SM 阵列(Streaming Multiprocessor) SM 0 线程块槽位 共享内存 寄存器堆 SM 1 线程块槽位 共享内存 寄存器堆 SM 2 线程块槽位 共享内存 寄存器堆 SM 3 线程块槽位 共享内存 寄存器堆 … 资源限制:maxThreadsPerSM / maxBlocksPerSM / 共享内存上限 分配 模型 独占 共享 MIG MPS 调度方向:集群 → 驱动 → 硬件;分配模型:整卡独占 / 多卡共享 / MIG切片 / MPS并发

二、调度器类型与策略

根据调度范围与决策频率,GPU调度器可分为三类,各自策略差异显著:

调度器类型 决策粒度 典型策略 适用场景
集群级调度器 容器 / 任务 / Pod Binpack(装箱)、Spread(扩散)、GPU拓扑感知 多租户AI平台、混合训练与推理
运行时调度器 CUDA Stream / Context 默认流串行、多流并发、优先级流 单卡多任务、流水线并行
硬件调度器 线程块 / Warp 硬件轮转、贪心填充SM、Warp级抢占 所有kernel执行

在集群层面,Binpack策略倾向于将任务尽量集中到少数GPU上,以释放空闲GPU供大任务使用;Spread策略则相反,将任务分散到多张GPU以降低故障爆炸半径。对于多卡训练任务,还需考虑NVLink拓扑亲和性——若两个通信频繁的进程被分配到跨PCIe Switch的GPU上,带宽可能下降30%以上。

三、资源分配模型:从独占到细粒度共享

现代GPU资源分配模型经历了从“整卡独占”到“细粒度切片”的演进,核心模型包括以下四种:

  1. 整卡独占(Exclusive):一个任务独占整张GPU,显存与计算完全隔离。优点是性能稳定、调试简单;缺点是利用率低,尤其对于推理等轻量任务。
  2. 时间切片(Time Slicing):多个任务轮流使用GPU,每个任务运行一个时间片。实现简单,但存在上下文切换开销,且不适合延迟敏感型任务。
  3. MIG(Multi-Instance GPU):A100/H100等硬件支持将GPU切分为多个独立实例,每个实例拥有专属的SM、显存带宽和L2缓存。硬件级隔离,性能可预期,但实例数量固定且无法动态调整。
  4. MPS(Multi-Process Service):允许多个进程共享同一GPU的SM,但显存仍各自独立。适合多个小batch推理任务并发,但需注意显存容量限制。
选型建议:若任务需要大显存(如训练70B模型),优先整卡独占;若在线推理服务有SLA要求,MIG是最佳选择;若离线批量推理可容忍波动,MPS或时间切片能显著提升吞吐。

四、案例:Kubernetes 下GPU调度配置

以下展示一个使用NVIDIA Device Plugin进行GPU资源分配的示例。假设集群中有4张A100(每张40GB显存),需要部署两个推理服务:

# 推理服务A:请求整卡独占
apiVersion: v1
kind: Pod
metadata:
  name: inference-a
spec:
  containers:
  - name: triton
    image: nvcr.io/nvidia/tritonserver:23.10
    resources:
      limits:
        nvidia.com/gpu: 1   # 独占1张A100
---
# 推理服务B:请求MIG切片(1g.5gb,约5GB显存)
apiVersion: v1
kind: Pod
metadata:
  name: inference-b
spec:
  containers:
  - name: triton
    image: nvcr.io/nvidia/tritonserver:23.10
    resources:
      limits:
        nvidia.com/mig-1g.5gb: 1   # 使用MIG实例

调度器根据资源请求与节点剩余资源进行匹配。若节点上已有Pod占用了2张整卡,剩余2张卡中,一张被MIG切片占用,则调度器会优先将服务A调度到空闲整卡上,将服务B调度到MIG实例所在节点。若未配置MIG,则服务B只能等待整卡释放。

五、常见误区与复盘

误区1:认为“GPU利用率高”等于“调度合理”。利用率高可能源于多个任务争抢SM导致相互干扰,实际吞吐反而下降。应同时观察SM活跃占比、显存带宽利用率和尾部延迟。
误区2:忽略显存分配对调度的影响。即使SM计算资源空闲,若显存不足,任务仍会排队。调度器必须同时考虑显存与计算资源,否则会出现“计算空闲但显存耗尽”的假性饱和。

复盘案例:某团队在K8s上运行多个PyTorch训练任务,发现GPU利用率仅40%。排查后发现:所有任务都请求了整卡独占,但每个任务实际只使用约10GB显存(卡容量40GB),且batch size较小,SM占用率低。调整为MPS共享后,将4个任务合并到2张GPU上,利用率提升至75%,同时释放出2张空闲卡供其他团队使用。此案例说明,资源分配模型的选择直接影响集群整体效率,需要结合任务实际资源画像进行决策。

最后需要强调:GPU调度不是“一次配置永久生效”的静态过程。随着业务负载变化,应定期复盘调度策略,利用nvidia-smi、DCGM等工具监控SM占用、显存带宽、MIG实例利用率等指标,动态调整资源分配模型,才能实现GPU集群的高效运转。