前言
前文Volcano 调度器 已经从宏观上分析了 Volcano 源码。Volcano Queue 是 Volcano 中最重要的 CRD 之一,其定义了资源的上下限(guarantee 和 capability)以及应得值(deserved)。从官方文档和字面理解来看,guarantee 是 queue 必须能够保证的值,也就是 pod 中的 request,capability 是 queue 最大所能获得的值,而 weight 决定了每个 Queue 在资源被占满的情况下应得的值。
然而,近期来细读源码发现,其实这三参数并没有想象的那么“有用”,本文一一道来。
挖源码
从源码中看 Volcano Queue 具有以下参数:
// QueueSpec represents the template of Queue.
type QueueSpec struct {
Weight int32
Capability v1.ResourceList
// Depreicated: replaced by status.State
State QueueState
// Reclaimable indicate whether the queue can be reclaimed by other queue
Reclaimable *bool
// extendCluster indicate the jobs in this Queue will be dispatched to these clusters.
ExtendClusters []Cluster
// Guarantee indicate configuration about resource reservation
Guarantee Guarantee `json:"guarantee,omitempty" protobuf:"bytes,4,opt,name=guarantee"`
// If specified, the queue's scheduling constraints
// +optional
Affinity *Affinity `json:"affinity,omitempty" protobuf:"bytes,6,opt,name=affinity"`
// Type define the type of queue
Type string `json:"type,omitempty" protobuf:"bytes,7,opt,name=type"`
// Parent define the parent of queue
// +optional
Parent string `json:"parent,omitempty" protobuf:"bytes,8,opt,name=parent"`
}
找源码的引用,发现 capability、guarantee 和 weight 主要是在 proportion Plugin 中被使用(admission 中没有做校验)。 因此进入到 proportion Plugin 中查看 OnSessionOpen 函数(前文有提到,Plugin 都是通过实现该函数影响调度)。
该函数的伪代码如下:
// 计算总资源量和总保证量
totalResource = sum{node.status.Allocatable} + OversubscriptionResource
totalGuarantee = sum(queue.guarantee)
// 计算 realCapability
for: all queues:
queue.realCapability = min(queue.capability, totalResource - totalGuarantee + queue.guarantee)
// 计算 queue 的 allocated, request
// ...
// 计算 deserve
for:
remain = totalResource
oldremain = remain
queue.deserved = remain * queue.weight / sum(queue.weight)
queue.deserved = max(queue.deserved, queue.guarantee)
increasedDeserved, decreasedDeserved = diff(queue.deserved, queue.oldDeserved) // 计算 deserved 变化值
remain = remain-queue.increasedDeserved+queue.decreasedDeserved
// 若 remain 被用光了,或者此次也无可调度了,则跳出循环
if remain==0 || oldremain == remain
break
// 注册各类钩子到 Action 中,影响 Enqueue 和 Allocate 逻辑
// ...
此处可以发现可以现象:
- Queue 的 capability 其实在调度时被替换过,则最终取得是和 totalResource - sum( 其他 queue.guarantee) 比较后的最小值,因此该值也是个不靠谱的值,并不是用户填了多少最终就能达到多少;
- Queue 的 weight 参数以 totalResource 为基准,根据分配计算出 Queue 的 deserved,然后该值最终会与 guarantee 做比较,取最大值,因此也是不靠谱的值;
- Queue 的 guarantee 不会在 admission 中做验证,而且并不直接参数到后期的各类钩子函数中,也是不靠谱的值,也就是说指定的 guarantee 并不一定能保证被分配到。
作者为了验证自己的猜想,去创建了一个 guarantee 为 10000 的 Queue,发现并没有做阻拦,此时明显是有问题的。
apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
name: queue-test
spec:
capability:
cpu: 15
guarantee:
resource:
cpu: 10000
reclaimable: true
weight: 3
结论
Volcano Queue 中的 capability、guarantee 和 weight 可能并不会像预期的那样工作。admission 并不会对 capability 和 guarantee 做校验,因此 guarantee 的值并不一定能得到保证,capability 也未必是真的最大值,而 weight 计算后的 deserved 值也会受 guarantee 所影响。因此在设置参数的时候需要用户自己去保证。
细心的读者可以发现,在指定合理的 capability 和 weight,不指定 guarantee 的情况下,大体还是能够符合用户需求的,而加入 guarantee 后带来了很多复杂性,且目前并没有被很好的解决。官方文档中也并没有针对 guarantee 做详细介绍,可能官方也认识该特性不是很成熟,不建议用户使用。