第 8 篇|Volcano 资源竞争:队列份额与作业调度
本文最后更新于:2 天前
前言
上一篇跟踪了一个 Volcano 作业的准入、试分配和绑定。这一篇加入第二个作业,集中回答三个问题:每个 Queue 可以继续使用多少资源,调度器先看谁,以及资源已经占满时怎样让等待成员继续运行。
主案例使用两个 Queue 和 12 核 CPU,先计算 Queue 份额,再看同一 Queue 内的作业怎样按 CPU、GPU 占用排序。默认流程是 enqueue, allocate, backfill,主动释放资源需要另外启用 preempt 或 reclaim。
Queue 表达什么
Queue 保存一组作业共享资源时使用的策略,并不对应固定的一组节点。要知道一个 Queue 还能否继续获得资源,需要把它的需求、当前占用和算出的份额放在一起看:
request:Queue 中已经分配和仍在等待的成员总共请求多少资源。allocated:已经进入 Allocated、Binding、Bound、Running 等状态的成员占了多少资源。weight:多个 Queue 都有未满足需求时,各自按多大比例参与份额计算。capability:这个 Queue 的份额上限。deserved:proportion 插件根据需求、权重和上限算出的本次份额。
guarantee 还可以为 Queue 设置保障量。它参与份额下限和可用上限的计算;主案例中 A 的保障量是 2 核,而按权重算出的份额是 4 核,所以它不会改变最终结果。
这些数字使用 Pod 声明的资源请求。一个 Pod 请求 2 核 CPU,即使进程此刻只用了 0.2 核,allocated 仍按 2 核计算。
用两个 Queue 计算一次份额
这里单独设定一组资源数量,不沿用第六篇的等大资源槽:集群共有 12 核 CPU,demo-job 属于 Queue A,demo-job-b 属于 Queue B。A 已占用 2 核,另有一个请求 2 核的成员等待;B 已占用 10 核。当前状态如下:
| Queue | weight | guarantee | capability | request | allocated |
|---|---|---|---|---|---|
A:ray-batch |
1 | 2 核 | 6 核 | 4 核 | 2 核 |
B:ray-batch-b |
2 | 0 | 10 核 | 10 核 | 10 核 |
weight 怎样得到 4 核和 8 核
proportion 从集群总量 12 核开始计算份额。此时这 12 核已经全部被 Pod 占用,计算要回答的是接下来各个 Queue 应分得多少。
A、B 的权重合计为 3。每三个等份中,A 按一份、B 按两份参与计算:
- A 增加的份额:12 × 1/3 = 4 核。
- B 增加的份额:12 × 2/3 = 8 核。
两边都没有超过各自的需求和上限,因此 deserved 最终是 4 核和 8 核。weight 影响的是份额计算,不会立即移动正在运行的 Pod,也不会直接绑定新的 Pod。
这段计算先按权重增加份额,再依次受可用上限和需求约束,最后考虑保障量。源码里的 realCapability 结合集群资源与各 Queue 的保障量计算可用上限,再受本 Queue 的 capability 限制。本例总保障量是 2 核,扣除后再加回本 Queue 的保障量:A 的上限为 min(12−2+2, 6)=6 核,B 为 min(12−2+0, 10)=10 核,恰好与表中的上限相同:
1 | |
如果 A 只需要 2 核,按权重得到的 4 核会被 request 截到 2 核,余下 2 核继续给仍有需求的 B,结果变成 2 核和 10 核。若 B 的上限又只有 7 核,最终是 2 核和 7 核,还有 3 核没有进入这两个 Queue 的 deserved。
这些余量分配都在同一次 proportion 计算中完成。
份额怎样影响下一次分配
proportion 用 allocated / deserved 计算 Queue 的份额使用率,源码中称为 share。主案例只看 CPU:
| Queue | allocated | deserved | share |
|---|---|---|---|
| A | 2 核 | 4 核 | 50% |
| B | 10 核 | 8 核 | 125% |
Queue 自身的调度优先级(priority)相同时,share 较小的 A 先被检查。B 的 125% 表示它当前占用超过了新算出的份额;重新计算 deserved 不会直接结束 B 中的 Pod。
A 中有一个等待成员请求 2 核。调度器会计算分配后的占用量是否超过 A 的 deserved:
1 | |
A 当前占 2 核,再增加 2 核正好达到 4 核,所以 Queue 额度允许继续。随后还要为这个成员寻找节点。由于集群的 12 核已经全部占用,它此时仍然无法直接绑定。
同一 Queue 内还有多个作业时
选中 Queue 后,如果里面有多个待调度作业,当前配置先比较 PriorityClass 所表达的作业优先级;优先级相同时,DRF(Dominant Resource Fairness,主导资源公平性)再比较各作业对 CPU、GPU 等资源的占用比例。它取各资源比例中的最大值作为主导份额,数值较小的作业排在前面。下图另用同一 Queue 内的两个作业说明这个比较,与前面的跨 Queue 份额计算分开。
因此,调度器先通过 Queue 规则选中 A,再在 A 内比较作业。DRF 参与后一层选择,A、B 的 4 核和 8 核份额仍由前面的 proportion 计算。
资源占满后怎样继续
默认的 enqueue, allocate, backfill 不会主动结束运行中的 Pod。需要释放资源时,Volcano 提供两条传统路径:
| Action | 范围 | 作用 |
|---|---|---|
preempt |
同一个 Queue 内 | 高优先级作业从同 Queue 的其他作业中选择可以退出的成员 |
reclaim |
不同 Queue 之间 | 份额不足的 Queue 从超过 deserved 且允许回收的 Queue 中选择成员 |
preempt 的跨作业候选首先要求双方属于同一个 Queue:
1 | |
回到主案例,A 的 deserved=4、allocated=2,还差 2 核;B 的 deserved=8、allocated=10,正好多占 2 核。如果启用 reclaim,并且 B 中有一个请求 2 核的成员通过优先级、可抢占性和 Gang 检查,调度器会按下面的顺序处理:
- 在 Statement 中记录要退出的 B 成员。
- 把 A 的等待成员标为 Pipelined,表示计划使用即将释放的资源,此时还没有绑定。
- 提交 Statement 后,B 的 Pod 开始终止,对应资源进入 Releasing。
- kubelet 完成终止,SchedulerCache 观察到资源释放后,A 的成员才会重新分配并绑定。
Gang 约束仍然参与成员筛选。如果移走一个成员会让 B 的作业低于 MinAvailable,这个成员不能用于本次回收。
小结:从 Queue 份额到 Pod 运行
资源竞争可以沿三步理解:proportion 根据需求、权重和上限计算 Queue 的 deserved;Queue 排序和额度检查决定先尝试谁;资源已经占满时,preempt 或 reclaim 才可能让等待成员获得未来资源。
份额计算、Pod 当前占用和节点空闲量是三件事。主案例中 A 有 2 核份额可用,但节点没有空闲 CPU;只有等待资源自然释放,或者完成一次符合条件的 reclaim,A 的成员才可能进入绑定。
下一篇回到 KubeRay,比较不开启批调度和接入 Volcano 后的两条创建流程。