Volcano 批调度在大模型离线评测中的应用:Gang Scheduling 实践
在企业大模型研发和持续迭代过程中,除了在线实时推理服务外,还存在着大量的离线批量计算负载——例如:每周例行对新训练的 Checkpoint 模型进行全量 Benchmark 评测(MMLU、GSM8K 等)、海量行业语料的批量 Embedding 向量化、自动化自动化 Red-Teaming 安全对抗评测。
这类离线任务通常是分布式的,往往需要同时拉起 8 个或 16 个 Pod,通过 NCCL 跨节点组网协同计算。
如果直接使用 Kubernetes 原生的kube-scheduler来管理这类分布式作业,经常会引发极其严重的死锁与算力饥饿(Deadlock & Starvation):
- 任务 A 申请了 8 个 GPU Pod,原生调度器先成功调度了其中的 4 个 Pod,但此时集群资源耗尽,剩下的 4 个 Pod 处于 Pending 状态;
- 此时任务 B 也申请了 8 个 GPU Pod,原生调度器又把刚空出来的 4 个 GPU 分给了任务 B 的前 4 个 Pod;
- 结果:任务 A 和任务 B 各自占有了 4 张卡,由于无法凑齐全部 8 张卡,两个分布式任务都无法启动,死锁僵持,白白占着昂贵的 GPU 资源空转烧钱。
为了解决多 Pod 协同作业的调度原子性问题,CNCF 孵化的云原生批调度引擎Volcano与其核心的Gang Scheduling(成组调度)机制成为了 AI 算力平台不可或缺的基石。
flowchart TD subgraph KubeScheduler[原生 K8s 调度器: 逐 Pod 调度缺陷] TaskA1[任务 A: 申请 8 卡] -.->|仅抢到 4 卡| Node1[卡槽 0-3: 占有锁死] TaskB1[任务 B: 申请 8 卡] -.->|仅抢到 4 卡| Node2[卡槽 4-7: 占有锁死] Note over TaskA1,TaskB1: 相互等待对方释放 -> 永久死锁与算力浪费 end subgraph VolcanoGang[Volcano Gang Scheduling: All-or-Nothing 原则] JobReq[分布式评测作业: 要求 minMember = 8] --> VolcanoCtrl[Volcano Scheduler 批调度器] VolcanoCtrl --> ResourceCheck{全集群是否有足额 8 张空闲卡?} ResourceCheck -->|不足 8 张卡| WaitAll[全量等待 0 占有: 保持 Pending] ResourceCheck -->|满足 8 张卡| AtomicAlloc[原子性一次性锁定 8 张卡并并发拉起] AtomicAlloc --> RunSuccess[所有 Worker 协同启动,零死锁秒级开始计算] end1. Gang Scheduling(成组调度)的核心哲学:All-or-Nothing
Gang Scheduling 的核心思想非常纯粹:“要么全部分配成功,要么一个都不分配(All-or-Nothing)”。
在 Volcano 体系中,一个分布式评测作业被抽象为一个VolcanoJob(或通过PodGroupCRD 管理):
minAvailable/minMember约束:用户在提交作业时,明确声明该任务启动所需的最小 Pod 数量(例如 8 个 Worker);- 原子性资源绑定:Volcano 调度器在执行调度计算时,只有当集群中能同时找到满足全部 8 个 Pod 运行的物理节点与 GPU 卡槽时,才会原子性地触发
Binding动作; - 彻底根除资源死锁:如果当前集群只有 6 张空闲卡,Volcano 会让该作业的所有 Pod 继续保持等待状态,绝不会预先分配这 6 张卡,从而让其他只需要 4 张卡的小型任务优先运行,极大提升了全集群的装箱率与周转效率。
2. 生产实战:定义分布式大模型评测作业
以下是一个标准的 Volcano 分布式评测 Job 声明:
apiVersion: batch.volcano.sh/v1alpha1 kind: Job metadata: name: llm-benchmark-eval-qwen72b namespace: ai-offline spec: minAvailable: 4 # 核心约束: 必须凑齐 4 个 Worker 才能一起启动 schedulerName: volcano # 指定使用 Volcano 调度器 plugins: env: [] svc: [] # 自动为分布式节点配置内部 DNS 发现与免密通信 tasks: - replicas: 4 name: worker policies: - event: PodFailed action: RestartJob # 任何一个评测节点异常退出,自动重置重启整组作业 template: spec: restartPolicy: OnFailure containers: - name: evaluator image: registry.internal.ai/eval/llm-benchmark:v2026.09 command: ["bash", "-c", "torchrun --nnodes=4 --nproc_per_node=8 eval.py"] resources: limits: nvidia.com/gpu: 8 cpu: "32" memory: "128Gi"3. 队列配额隔离与借调(Queue Capacity & Reclaim)
除了 Gang 调度外,Volcano 还提供了强大的层级队列(Hierarchical Queue)与资源借调机制:
apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: offline-eval-queue spec: weight: 30 # 调度权重 capability: nvidia.com/gpu: 64 # 队列保障的基础配额 (Quota) reclaimable: true # 允许被高优先级的在线队列抢占借调- 空闲借调:当在线推理队列在夜间低谷期有大量空闲 GPU 时,离线评测队列可以自动“借用”这部分算力,将离线评测并发度拉满;
- 快速归还:第二天早高峰在线流量激增时,Volcano 会在 30 秒内触发优雅驱逐,将借用的算力归还给在线服务。
4. 治理收益与落地成效
引入 Volcano 批调度后,我们算力平台的离线作业运行指标取得了显著提升:
- 分布式评测作业死锁率:从先前的每周 3~5 次直接降为 0;
- 全集群 GPU 综合利用率:通过错峰算力借调与弹性填谷,集群整体算力利用率从 42% 大幅攀升至78%;
- 离线作业周转时长(Turnaround Time):评测任务排队与计算周期平均缩短了 35%。