Volcano Agent Scheduler 调度队列深度解析:Kubernetes 调度队列的移植、定制与升级实践

发布时间:2026/9/17 1:20:41
Volcano Agent Scheduler 调度队列深度解析:Kubernetes 调度队列的移植、定制与升级实践 Volcano Agent Scheduler 调度队列深度解析Kubernetes 调度队列的移植、定制与升级实践【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcanoVolcano 的 Agent Scheduler快速路径调度器需要一个高速且可靠的 Pod 排队机制来支撑多 Worker 并发调度场景。本文将基于 third_party/kubernetes/pkg/scheduler/backend/queue/README.md 及其目录下的真实实现完整讲解该调度队列的移植来源、三组件activeQ / backoffQ / unschedulablePods架构、关键参数与接口、Volcano 特有的冲突紧急重试增强以及从 v1.34 上游版本向上迁移升级的两种实操方案。读完本文你将掌握 Volcano 调度队列的底层原理、配置入口和升级维护方法能够在自己的集群中定位排队行为并安全地执行版本跟进。背景为何 Agent Scheduler 需要一个久经考验的调度队列Volcano Agent Scheduler 的设计目标是成为面向 Agent 工作负载的快速路径调度器。正如 docs/design/agent-scheduler.md 所述其核心设计之一是Multi-Worker 并行调度多个 Worker 同时从中央调度队列中取出 Pod 进行调度采用乐观并行策略agent_scheduler_worker_countx可配置 Worker 数量。在这种高吞吐、高并发的模型下Pod 排队机制的速度和可靠性直接决定了整个调度器的吞吐上限。与其从零自研一套排队逻辑Volcano 选择了直接采用 Kubernetes kube-scheduler 经过多年生产验证的调度队列实现。该队列位于 Kubernetes 仓库的pkg/scheduler/backend/queue包移植时对应的上游版本为v1.34。Volcano 在尊重并保留上游成熟实现的基础上继续围绕自身场景进行迭代增强这正是本目录存在的意义——站在巨人的肩膀上而不是重新发明轮子。移植内容清单third_party 目录里到底放了什么该队列的移植代码统一存放在 third_party/kubernetes/pkg/scheduler/backend/queue 目录下与 Kubernetes 上游包路径保持一一对应便于日后比对升级。完整清单如下文件职责scheduling_queue.go调度队列主实现定义SchedulingQueue接口与PriorityQueue结构active_queue.go就绪队列activeQ存放可以立即调度的 Podbackoff_queue.go退避队列backoffQ对需要指数退避重试的 Pod 进行管理unschedulable_pods.go不可调度 Pod 池unschedulablePods管理调度失败且当前条件下不可调度的 Pod*_test.go对应的单元测试scheduling_queue_test.go、active_queue_test.go、backoff_queue_test.go、unschedulable_pods_test.go及辅助的testing.go这些文件完全保留了 Kubernetes 上游的 Apache License 2.0 版权头与作者署名移植的可追溯性做得非常规范——任何代码都可以直接与上游对应文件逐行比对。三组件队列架构activeQ、backoffQ 与 unschedulablePodsPriorityQueue 的核心数据结构在 scheduling_queue.go 中PriorityQueue被明确定义为由两个子队列和一个附加数据结构组成type PriorityQueue struct { stop chan struct{} clock clock.WithTicker lock sync.RWMutex podMaxInUnschedulablePodsDuration time.Duration activeQ activeQueuer backoffQ backoffQueuer unschedulablePods *unschedulablePods moveRequestCycle int64 preEnqueuePluginMap map[string]map[string]schedfwk.PreEnqueuePlugin queueingHintMap QueueingHintMapPerProfile pluginToEventsMap map[string][]schedfwk.ClusterEvent ... }activeQ持有等待被调度的 Pod队头永远是优先级最高的待调度 Pod调度循环通过Pop()从队头取任务。backoffQ持有有潜在可调度机会但仍在退避期内的 Pod。当集群事件如节点更新、Pod 删除使某些不可调度 Pod 变得可能可调度时这些 Pod 先进入 backoffQ等待退避时间到期后再转入 activeQ从而避免高频重试压垮调度器。unschedulablePods持有已经被尝试调度过、并在当前集群条件下被判定为不可调度的 Pod等待后续事件触发唤醒。三者之间通过moveRequestCycle收到 move 请求时的调度周期号等机制协调保证 Pod 不会重复出现在多个队列中。Pod 在队列间的流转生命周期结合 docs/design/agent-scheduler.md 的队列工作流描述Pod 的完整流转过程为监听到新的待调度 Pod 后将其加入activeQ随后被Pop()取出尝试调度若调度失败Pod 被放入unschedulablePods池集群事件发生时调度器检查 unschedulablePods 池Pod 仍在退避期内 → 移入backoffQ等待退避到期退避期已过 → 直接移入activeQ绑定冲突场景见下文冲突紧急重试时Pod 被标记高优先级并立即插回activeQ队头绕过退避周期快速重试。退避窗口对齐机制值得注意的细节是 backoff_queue.go 中定义的backoffQOrderingWindowDuration1 秒。backoffQ 按秒级排序窗口组织 Pod——每个窗口内按优先级排序且从 backoffQ 向 activeQ 冲刷时以整个窗口为单位、对齐到整秒边界执行避免冲刷产生可见延迟。这一设计对应 Kubernetes 上游的 KEP-5142Volcano 移植后完整保留。SchedulingQueue 接口队列的完整 API 全景SchedulingQueue 接口 定义了调度队列对外暴露的全部能力理解它是理解调度主循环的前提方法作用Add将 Pod 加入队列Activate将指定 Pod 移动到 activeQ若 Pod 处于 in-flight 状态则注册通配事件以便回队AddUnschedulableIfNotPresent将不可调度的 Pod 加回队列携带当前调度周期号SchedulingCycle返回当前调度周期号每次Pop自增Pop/Done取出队头 Pod / 标记 Pod 处理完成两者配合跟踪 in-flight PodUpdate/Delete更新 / 删除队列中的 PodMoveAllToActiveOrBackoffQueue事件触发时将满足 preCheck 的 Pod 全部移到 activeQ 或 backoffQAssignedPodAdded/AssignedPodUpdated处理已调度 Pod 的添加/更新事件用于唤醒受影响的 PodClose/Run关闭队列 / 启动队列后台管理 goroutinePatchPodStatus通过 API Dispatcher 发送 Pod 状态更新仅在SchedulerAsyncAPICallsfeature gate 开启时使用GetPod/PendingPods/InFlightPods/PodsInActiveQ/PodsInBackoffQ/UnschedulablePods测试与调试用的查询接口从源码结构看该接口的设计刻意贴近cache.FIFO与cache.Heap的模式使上游数据结构可以直接作为SchedulingQueue使用这也为 Volcano 后续复用 Kubernetes 调度队列生态如 QueueingHint保留了空间。关键默认参数退避时长与驻留上限上游默认值scheduling_queue.go 定义了三个核心时序参数及其默认值// Pod 在 unschedulablePods 中的最长驻留时间超过后会被移到 backoffQ 或 activeQ DefaultPodMaxInUnschedulablePodsDuration time.Duration 5 * time.Minute // 不可调度 Pod 的初始退避时长 DefaultPodInitialBackoffDuration time.Duration 1 * time.Second // 不可调度 Pod 的最大退避时长 DefaultPodMaxBackoffDuration time.Duration 10 * time.Second即调度失败的 Pod 首次退避 1 秒随后按指数递增封顶 10 秒在 unschedulablePods 池中最多驻留 5 分钟超时后无论是否有事件触发都会被重新唤醒尝试。Volcano 侧的配置入口在 Agent Scheduler 的缓存初始化中这些参数通过 Option 模式注入队列。见 pkg/agentscheduler/cache/cache.gosc.schedulingQueue k8sschedulingqueue.NewSchedulingQueue( Less, sc.informerFactory, k8sschedulingqueue.WithClock(defaultSchedulerOptions.clock), k8sschedulingqueue.WithPodInitialBackoffDuration(time.Duration(defaultSchedulerOptions.podInitialBackoffSeconds)*time.Second), k8sschedulingqueue.WithPodMaxBackoffDuration(time.Duration(defaultSchedulerOptions.podMaxBackoffSeconds)*time.Second), k8sschedulingqueue.WithPodMaxInUnschedulablePodsDuration(defaultSchedulerOptions.podMaxInUnschedulablePodsDuration), k8sschedulingqueue.WithMetricsRecorder(metricsRecorder), k8sschedulingqueue.WithQueueingHintMapPerProfile(queueingHintMapPerProfile), )默认值定义在 pkg/agentscheduler/cache/util.go 中直接取自上游队列包的常量初始退避 1s、最大退避 10s、unschedulable 驻留 5min。这意味着 Volcano 复用了 Kubernetes 的默认行为Less函数用于决定 activeQ 中 Pod 的优先级排序队头最高优先级先被调度。另外Volcano 通过WithQueueingHintMapPerProfile为调度器注册了 Queueing Hint 映射。buildQueueingHintMap 目前注册了一个通配事件WildCard All并绑定defaultQueueingHintFn恒定返回Queue即应该入队。从源码注释看这只是一个基础起点后续可以扩展更细粒度的事件与队列提示函数来精确控制 Pod 的入队时机。Volcano 的本地化定制移除 NominatedNode 与冲突紧急重试移除 NominatedNode 逻辑Volcano 对上游队列做的核心修改在 README 中明确列出移除了所有NominatedNode相关代码与 Pod 提名逻辑。NominatedNode 是 kube-scheduler 中预选候选节点机制的一部分在 Volcano Agent Scheduler 的架构中候选节点的记录、冲突检测与最终绑定统一由独立的 Binder 组件ConflictAwareBinder负责不再需要队列侧维护提名状态从而精简了队列内部的数据结构和事件处理路径。这一点在 pkg/agentscheduler/cache/cache.go 中可以看到ConflictAwareBinder NewConflictAwareBinder(sc, sc.schedulingQueue)即 Binder 直接持有调度队列引用用于在冲突时将 Pod 重新推回队列。冲突紧急重试Urgent Retry Mechanism与原生 kube-scheduler 相比Volcano 引入的关键增强是绑定冲突的紧急重试机制。在多 Worker 乐观并发调度下多个 Worker 可能同时选中同一节点并各自执行 Bind产生乐观并发冲突。当 Conflict-Aware Binder 检测到冲突时会将 Pod 以提升后的内部优先级如SchedulingPriorityUrgent立即重新推入activeQ 队头使其绕过正常的退避周期、优先于其他待调度 Pod 被重新调度从而把乐观并发碰撞带来的延迟影响降到最低。与 Agent Scheduler 调度主循环的集成调度队列在 Agent Scheduler 的每个调度周期中扮演枢纽角色。在 pkg/agentscheduler/scheduler.go 的generateNextSchedulingContext中queue : worker.framework.Cache.SchedulingQueue() ... podInfo, err : queue.Pop(klog.Background()) if err ! nil { return nil, fmt.Errorf(failed to pop scheduling task: %w, err) } task, exist : worker.framework.Cache.GetTaskInfo(schedulingapi.TaskID(podInfo.Pod.UID)) if !exist { queue.Done(podInfo.Pod.UID) // Pod 已不在缓存中标记完成并跳过 return nil, nil }调度主循环runOnce在快照更新失败等异常路径下会调用queue.AddUnschedulableIfNotPresent(klog.Background(), schedCtx.QueuedPodInfo, queue.SchedulingCycle())将 Pod 安全地放回调度队列等待下一轮重试见 scheduler.go。SchedulingQueue()由 cache.go 暴露给 Worker 使用。可以看到Worker 的调度循环与队列之间的交互完全遵循 kube-scheduler 的经典模式Pop → 调度 → 成功则 Bind / 失败则 AddUnschedulableIfNotPresent → Done。这也是该队列经过实战检验价值的最直接体现。升级策略从 v1.34 向上迁移的两种方案由于该目录是手动拷贝非 vendor 自动管理升级必须手动干预。README 给出了两种明确的升级方案Option 1应用 Diff适合小版本升级在 Kubernetes 上游仓库中先生成相邻版本间队列包的差异再手动应用到 Volcano 的 third_party 目录# 在 kubernetes 仓库中执行 git diff v1.35.0..v1.36.0 -- pkg/scheduler/backend/queue然后将输出 diff 手动应用到 third_party/kubernetes/pkg/scheduler/backend/queue并保持 Volcano 侧的定制修改不丢失。Option 2整体替换文件适合大版本升级删除本目录下的所有文件从上游pkg/scheduler/backend/queue拷贝新版本文件重新应用定制修改——即再次移除NominatedNode相关代码与 Pod 提名逻辑更新本 README 中的上游版本号保持版本可追溯。无论采用哪种方式README 都强调升级完成后必须更新版本号这是保证手动拷贝模式可维护性的关键纪律。测试保障与实现一一对应的单元测试该目录同时移植了上游的完整单元测试包括scheduling_queue_test.go — 队列主逻辑、事件驱动迁移、接口行为测试active_queue_test.go — activeQ 的 add/update/delete/pop 行为测试backoff_queue_test.go — 退避计算与窗口冲刷测试unschedulable_pods_test.go — 不可调度 Pod 池管理测试testing.go — 测试辅助构造。此外Agent Scheduler 侧的 cache/binder_test.go 等测试也直接以k8sschedulingqueue.WithPodInitialBackoffDuration(...)等 Option 构造队列实例进行集成验证。测试代码与实现一一对应既保障了移植后的行为与上游一致也为升级时的回归验证提供了基础。许可证说明该目录下的代码与 Kubernetes 项目保持一致遵循Apache License 2.0许可见各文件头部的版权声明。移植时完整保留了 Kubernetes 作者的版权声明符合开源许可证的署名与再分发要求。总结Volcano Agent Scheduler 的调度队列是一次教科书式的成熟组件复用实践以 Kubernetes v1.34pkg/scheduler/backend/queue为蓝本完整继承其 activeQ / backoffQ / unschedulablePods 三组件架构、指数退避与事件驱动唤醒机制再针对自身多 Worker 乐观并发的架构特点移除提名逻辑、引入冲突紧急重试与 Queueing Hint 映射。对于希望深入理解 Volcano 排队机制或计划维护该组件的开发者queue 目录、agent-scheduler 设计文档 以及 cache 初始化代码 构成了从设计到实现的完整阅读链路。【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcano创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询