Volcano Agent Scheduler 设计解析:面向 AI Agent 负载的 Kubernetes 快速路径调度器
2026/9/17 11:25:08 网站建设 项目流程

Volcano Agent Scheduler 设计解析:面向 AI Agent 负载的 Kubernetes 快速路径调度器

【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcano

本文以 Volcano 项目设计文档 docs/design/agent-scheduler.md 为主体,结合 pkg/agentscheduler、cmd/agent-scheduler 等仓库源码展开。读者将完整理解 Agent Scheduler 的提出动机、总体架构、调度队列、多 Worker 并行调度与 Binder 冲突解决机制、NodeShard 分片同步机制,以及 none/soft/hard 三种分片模式的配置方法,并掌握从 Helm 部署到启动参数调优的完整实操路径。

一、背景与问题:为什么 Volcano 需要一个 Agent Scheduler

Volcano Scheduler 是为大数据、HPC、ML、AI 框架等批量和弹性负载设计和优化的调度器,提供高性能调度以及丰富的调度策略与算法。但并非所有负载都需要批式调度特性——有些负载的调度诉求恰恰是 Volcano 现有模型难以满足的。文档以AI Agent 负载为例,指出两个核心矛盾:

  1. 延迟敏感与高频建任务:Agent 负载延迟敏感、任务创建频繁。调度器必须处理海量任务并做到超快调度,在保证高吞吐的同时维持单任务低调度延迟;当 Agent 负载与其他负载混部在同一集群时,延迟同样需要被保障。而 Volcano 调度器在每个调度会话内按固定时间间隔批量处理负载,Pod 无法被立即调度;存在其他负载时,任务必须按序排队,调度延迟无法得到保证。
  2. 调度策略差异化:Agent 的调度策略可能与其他负载不同。Agent 负载可能不需要拓扑打散(topology spread)或 Pod 亲和(pod affinity),反而可以调度到资源较小或碎片化的节点上,从而更好地利用资源碎片、提升集群整体效率。这要求不同负载能够配置不同的调度策略。

从源码结构看,Agent Scheduler 的入口位于 cmd/agent-scheduler/main.go,其核心调度逻辑集中在 pkg/agentscheduler/scheduler.go 中定义的AgentScheduler,它是一个独立的调度器进程,通过--scheduler-name(默认agent-scheduler)识别并接管spec.schedulerName与其一致的 Pod(见 cmd/agent-scheduler/app/options/options.go)。

二、设计目标与总体架构

设计目标

文档明确了两个设计目标:

  1. 能快速调度海量 Pod 的调度器:通过工作流优化与策略简化提升调度效率。
  2. 能与 Volcano 调度器协作、处理不同类型负载的调度器:通过基于分片(shard)的并行调度实现调度器之间的协作与资源管理。

架构总览

系统引入一个独立的Agent Scheduler来识别并对 Agent 负载做快速调度。它通过优化调度策略与"即时调度"(in-time scheduling)提升单个 Pod 的调度速率,并通过多 Worker 并行调度进一步提升整体调度吞吐。当 Agent 负载与其他负载共存时,Sharding Controller根据资源阈值、节点类型等策略动态将节点划分为分片,各调度器通过分片同步获得可调度节点,并选择/优选出对应节点进行调度,从而实现多调度器基于不同分片的并行调度。分片控制器设计与分片策略详见 sharding controller design and shard strategy。

架构中的三个核心组件:

  • Sharding Controller:根据集群节点资源状态与分片策略,动态将集群节点分配到不同分片。
  • Agent Fast-Path Scheduler:对对应分片内的 Pod(或优先在分片内)执行快速调度。它使用并发调度(多 Worker)提升任务吞吐,并优化调度流程与策略以提高调度效率。
  • Volcano Scheduler:支持与 Agent Scheduler 对不同类型负载做协同调度。引入 Sharding Coordinator 从 NodeShard 同步节点;一旦启用分片调度,Volcano Scheduler 也在对应分片内(或优先在分片内)调度 Pod。

三、调度框架:Scheduler、Worker、Framework、Snapshot、Action 与 Plugin

Agent Scheduler 的调度框架包含完整的调度工作流、调度队列以及 Plugin/Action 机制设计。

组件层次结构

系统架构依赖严格的层次关系与初始化顺序:

  • Scheduler:顶层组件,管理整个调度系统的生命周期,拥有 Cache、配置(Configurations)和 Worker Pool。
  • Worker:并发调度单元。每个 Worker 相互独立,各自持有独立的 Framework 实例。多个 Worker 会同时从中央调度队列取出 Pod 进行调度,采用乐观并行调度(optimistic parallel scheduling)。
  • Framework:Worker 内插件的运行环境,持有 Plugin 与 Action 的注册表,并维护该 Worker 当前调度周期专属的集群状态Snapshot
  • Snapshot:由全局 Cache 派生的集群状态(节点、Pod 等)的时间点视图。每个 Worker 在调度周期开始时更新自己的 Snapshot 以保证一致性。
  • Action:定义高层调度逻辑(如 Allocate),按照既定顺序编排多个 Plugin 的执行。
  • Plugin:实现具体调度算法(如 Predicates、NodeOrder),注册在 Framework 中并由 Action 调用。

初始化序列

初始化过程从Scheduler开始:首先建立全局Cache与 Kubernetes API server 同步;然后加载调度配置以确定启用的 Action 与 Plugin;随后初始化Worker Pool。每个Worker被创建时都会实例化一个独立的Framework。运行时,Worker 在开始一个调度周期前,先从全局 Cache 更新其 Framework 的Snapshot,为后续 Action 与 Plugin 的执行提供一致视图。

这段设计与源码完全对应:在 pkg/agentscheduler/scheduler.go 的Run中,调度器先loadSchedulerConf()加载配置,随后sched.cache.Run(stopCh)启动 Cache,再循环创建workerCountWorker,每个 Worker 通过framework.NewFramework(...)创建独立的 Framework 实例并启动独立的 goroutine 循环执行worker.runOnce()。而 runOnce 中先执行worker.framework.Cache.UpdateSnapshot(snapshot)更新 Snapshot,再依次执行各 Action——这正是"周期开始时更新 Snapshot"的直接实现。SchedulingContext中携带了TaskQueuedPodInfoNodesInShard(分片内节点集合),见 pkg/agentscheduler/api/types.go。

四、调度队列:activeQ、backoffQ 与不可调度 Pod 池

设计渊源

调度队列的设计大量借鉴并直接参考了成熟的 kube-scheduler 队列架构。由于 Volcano 快速路径调度器的设计目标与 kube-scheduler 的队列管理原则高度一致,选择在这一成熟架构之上快速构建面向 Agent 负载的健壮、高效的调度框架。

队列架构

调度队列管理 Pod 的执行顺序,由三个组件构成:

  • ActiveQ:存放立即可调度的 Pod。
  • BackoffQ:存放潜在可调度(如被集群事件触发)但需等待 backoff 周期结束的 Pod。这防止调度器被频繁重试淹没,保证调度吞吐。
  • Unschedulable Pods Pool:存放调度失败、在当前集群条件下判定为不可调度的 Pod。

绑定冲突的紧急重试机制

相对标准队列逻辑的一个关键增强是绑定冲突紧急重试机制(Urgent Retry Mechanism)。当Conflict-Aware Binder检测到冲突(即多个 Worker 尝试绑定到同一节点)时,会将 Pod 以更高的内部优先级(如SchedulingPriorityUrgent)重新推回ActiveQ,确保冲突 Pod 优先于其他待调度 Pod 被立即重调度,最小化乐观并发碰撞带来的延迟影响。

队列工作流

  1. 监听到新的未调度 Pod 时,将其加入activeQ,随后从 activeQ 弹出并尝试调度。
  2. 若调度失败,Pod 被加入unschedulable pods pool
  3. 当集群事件发生(如节点更新、Pod 删除等)时,调度器检查 unschedulable pods pool 中的 Pod:
    • 若事件使 Pod 变为潜在可调度且仍处于 backoff 周期内,则移入backoffQ等待 backoff 到期;
    • 若 backoff 周期已过,则直接移入activeQ
  4. 发生绑定冲突时:Pod 被标记高优先级标签并立即重新加入activeQ队首,绕过 backoff 周期快速重试调度。

五、多 Worker 并行调度与 Binder 冲突处理

单个调度进程在处理海量 Pod 时存在性能瓶颈。为提升调度吞吐,可启用多个 Worker 并行调度。Worker 数量可通过启动参数--scheduler-worker-count=x配置(该参数在 Helm values 中的对应键为agent_scheduler_worker_count)。并行调度在集群资源不足时可能带来调度冲突,因此引入Binder组件在实际绑定前解决冲突。

调度与绑定流程

Worker 从调度队列弹出 Pod 并执行调度。经过谓词过滤(predicates)与节点排序(node ordering)后,将多个候选节点(数量可配置)存入调度结果用于分配。调度结果随后交给Binder做最终绑定。Binder 处理来自多个 Worker 的分配结果,使用乐观并发控制解决调度冲突,对无冲突的结果执行 Bind。

具体流程分五步:

  1. 每个调度结果记录不止一个可分配节点(数量可配置),并记录每个节点在分配时的绑定版本(binding version)。
  2. Binder 按顺序检查调度结果中的节点。若该节点的绑定版本在之前的 Bind 中未被使用过,则 Binder 对该 Pod(如 Pod A)在该节点执行 Bind,并更新该节点的绑定版本。
  3. 若某节点上的绑定版本已被之前的 Bind 使用过,Binder 检查分配结果中的下一个可用节点;若无冲突则在该节点执行 Bind 并更新绑定版本。例如:node1(v1) 在上一次绑定中分配给了 Pod A,Worker 2 在为 Pod B 分配 node1 时未考虑 Pod A,因此若 Pod B 仍绑定到 node1 可能冲突,此时 Binder 为 Pod B 选择 node2。
  4. 若结果中所有节点都不可用,Pod 以高优先级被推回调度队列重调度。例如:为 Pod C 分配的两个节点都基于此前绑定已使用过的 v1,两个节点均被 Binder 拒绝,Pod C 被推回队列。
  5. 若新分配基于节点更新后的绑定版本,Binder 认为该分配基于节点的最新资源视图,允许绑定。例如:node1(v2) 在已包含之前绑定 Pod 信息的基础上分配给 Pod D,不视为冲突。

从源码看,候选节点数由 allocate Action 的candidateNodeCount参数控制,默认值为 3(DefaultCandidateNodeCount = 3),可通过配置项candidateNodeCount调整,见 pkg/agentscheduler/actions/allocate/allocate.go。调度结果通过PodScheduleResult(含SuggestedNodes候选节点列表)传递给 Binder,见 pkg/agentscheduler/api/types.go。

六、分片同步机制:NodeShard 与协调器

分片内的节点保存在NodeShard自定义资源中,且可能动态变化,因此调度器需要感知这些变化以确定可用于调度的节点。调度器还需要与其他调度器协调,确保同一节点不会同时出现在不同调度器的调度缓存中——因为调度器缓存中使用的节点与 Shard 定义中的节点可能不一致。

NodeShard 示例

apiVersion: shard.volcano.sh/v1alpha1 kind: NodeShard metadata: name: volcano spec: nodesDesired: #Nodes should be used within this shard. - node1 - node2 - node3 status lastUpdateTime: "2025-12-08T06:00:00Z" nodesInUse: #Node being used by scheduler. - node0 - node1 - node2 nodesToRemove: #Node should be remove from scheduler. (nodes is being used by scheduler, so they cannot be removed from InUse list immediately) - node0 nodesToAdd: #Node should be added to scheduler. (nodes is being used by other schedulers, so they cannot be add into InUse list immediately) - node3 --- apiVersion: shard.volcano.sh/v1alpha1 kind: NodeShard metadata: name: agent-scheduler spec: nodesDesired: #Nodes should be used within this shard. - node0 - node4 - node5 status lastUpdateTime: "2025-12-08T06:00:00Z" nodesInUse: #Node being used by scheduler. - node4 - node5 nodesToAdd: #Node should be added to scheduler. (nodes is being used by other schedulers, so they cannot be add into InUse list immediately) - node0

NodeShard 中几个关键字段的含义:

  • spec.nodesDesired:该分片期望使用的节点集合(分片策略的计算结果)。
  • status.nodesInUse:当前正被调度器使用的节点。
  • status.nodesToRemove:应从调度器移除的节点。由于节点正被调度器使用,不能立刻从 InUse 列表中删除。
  • status.nodesToAdd:应加入调度器的节点。由于节点正被其他调度器使用,不能立刻加入 InUse 列表。

调度器如何消费分片信息

  • Agent Scheduler:调度前,Worker 从 Sharding Coordinator 获取当前调度周期可用的节点。Coordinator 与 NodeShard 保持同步,计算当前 Scheduler 可用的节点集合。
  • Volcano Scheduler:Session 打开后,调度器从 Snapshot 获取当前会话可用节点。Sharding Coordinator 与 NodeShard 保持同步并计算可用节点,可用节点被缓存在调度器 Cache 中,并通过 Snapshot 传入 Session。

在 Agent Scheduler 中,分片内节点集合随调度上下文传递:SchedulingContext.NodesInShard记录了当前调度器的分片节点集合,allocate Action 在谓词过滤与节点排序时都会结合NodesInShard进行(见 pkg/agentscheduler/actions/allocate/allocate.go)。

分片协调器(Sharding Coordinator)

每个调度器内部都需要一个协调器(coordinator),用于检测 NodeShard 的变化计算下一调度周期可用的节点。基于不同分片中节点的 in-use 状态以及分配给本调度器分片的节点,协调器计算本调度器下一轮调度可用的节点,并更新 NodeShard 以告知其他调度器哪些节点正在被使用。

Agent Scheduler 中的协调器:监听 NodeShard 变化并计算可用节点。在所有调度 Worker 完成可用节点同步后,协调器更新 NodeShard 的NodesInUse/NodesToRemove/NodesToAdd字段:

  • 若 NodeShard 变化时没有 Worker 正在调度,协调器直接计算可调度节点并用新列表更新上述三个字段。
  • 若 NodeShard 变化时有 Worker 正在调度,协调器不能立即更新字段(因为 Worker 当前使用的节点可能包含其他节点)。只有当某个 Worker 完成一个调度周期、且没有其他 Worker 正在调度、或所有 Worker 都已开始使用协调器在变化后计算出的节点时,协调器才用新计算的可用节点更新字段。

Volcano Scheduler 中的协调器:同样监听 NodeShard 变化并计算可用节点。若没有 Session 运行,协调器立即更新NodesInUse/NodesToRemove/NodesToAdd字段;若有 Session 运行,为避免 NodeShard 中的节点与 Session 中的节点不一致,协调器阻塞更新直到 Session 关闭,Session 关闭后唤醒更新流程。

七、分片模式配置:none / soft / hard

分片模式通过启动参数--scheduler-sharding-mode=xxx配置,可选值为nonesofthard,调度行为随配置不同而不同(默认值为none,对应常量util.NoneShardingMode,见 cmd/agent-scheduler/app/options/options.go):

  • none(默认):不应用分片。调度器可在整个集群范围调度。
  • soft(软隔离):调度器感知集群全部节点,但优先将 Pod 调度到自身分片内的节点以避免冲突;仅当分片内没有满足 Pod 需求的节点时,才考虑其他分片的节点,此时调度冲突交由 kubelet 处理。由于节点在分片内被优先排序,调度的全局最优性可能略有下降。
  • hard(硬隔离):调度器只能将 Pod 调度到自身分片内的节点,与其他调度器完全避免冲突。但由于调度范围受限,调度的全局最优性可能进一步下降。

默认情况下,调度器读取与调度器同名(scheduler name)的 NodeShard 获取分片信息。也可通过启动参数--scheduler-sharding-name=xxx指定分片名,调度器将读取指定名称的 NodeShard(该参数在 Helm values 中的对应键为agent_scheduler_sharding_name)。从源码确认,Agent Scheduler 的默认调度器名与默认分片名均为agent-scheduler(见 cmd/agent-scheduler/app/options/options.go)。

八、Agent Scheduler 的部署与启动参数

文档中"Agent Scheduler Configuration"章节标注为 TBD,但仓库中已具备完整的部署与配置实现,可整理如下。

Helm 部署

Agent Scheduler 作为 Volcano Helm Chart 的可选组件部署。在 installer/helm/chart/volcano/values.yaml 中设置custom.agent_scheduler_enable: true即可启用,相关模板见 installer/helm/chart/volcano/templates/agent_scheduler.yaml。

默认调度配置(ConfigMap 中的agent-scheduler.conf)极为精简,体现了"策略简化"的设计目标:

actions: "allocate" tiers: - plugins: - name: predicates - name: nodeorder

即默认只启用allocate一个 Action 与predicatesnodeorder两个 Plugin,可通过custom.scheduler_config_override覆盖(见 installer/helm/chart/volcano/templates/agent_scheduler.yaml)。

常用启动参数(以当前仓库源码为准)

根据 cmd/agent-scheduler/app/options/options.go,Agent Scheduler 的核心启动参数如下:

参数默认值说明
--scheduler-nameagent-scheduler该调度器接管spec.schedulerName与之相同的 Pod
--scheduler-conf调度配置文件绝对路径(配置 Action 与 Plugin)
--scheduler-worker-count1并行调度 Worker 线程数(Helm values 对应键agent_scheduler_worker_count
--scheduler-sharding-modenone分片模式:none/soft/hard
--scheduler-sharding-nameagent-scheduler本调度器使用的分片名(Helm values 对应键agent_scheduler_sharding_name
--minimum-feasible-nodes100需查找与评分的最少可行节点数
--minimum-percentage-nodes-to-find5需查找与评分的节点最小百分比
--percentage-nodes-to-find0每调度周期评分的节点百分比,<=0时按集群规模自适应计算
--node-worker-threads20同步节点操作的线程数
--kube-api-qps/--kube-api-burst2000/2000与 Kubernetes API server 通信的 QPS 与 Burst
--enable-healthz/--enable-metricsfalse是否启用健康检查 / 指标
--resource-sync-timeout60s启动调度前等待初始资源同步的超时时间,0表示跳过等待
--leader-elect见 Helm 值是否启用 leader election 高可用
--cache-dump-dir/tmpCache dump 输出的 json 文件目录
--scheduler-sharding-nameagent-scheduler指定 NodeShard 名称

其中--scheduler-worker-count对应文档中的agent_scheduler_worker_count=x表述——后者实际是 Helm values.yaml 中的键名,最终通过模板渲染为启动参数--scheduler-worker-count(见 installer/helm/chart/volcano/templates/agent_scheduler.yaml)。同理,文档中的--agent_scheduler_sharding_name=xxx对应实际启动参数--scheduler-sharding-name。使用前请以当前仓库 cmd/agent-scheduler/app/options/options.go 为准。

另外,--scheduler-worker-count必须大于 0,否则启动校验失败(见 cmd/agent-scheduler/app/options/options.go)。

调度配置热更新

Agent Scheduler 支持调度配置热更新:指定--scheduler-conf后,调度器会通过文件监听(pkg/filewatcher/filewatcher.go)监控配置文件,检测到写入或创建事件时重新加载配置并更新 metrics 配置(见 pkg/agentscheduler/scheduler.go)。若未提供配置文件且未禁用默认配置回退,则使用内置默认配置;--disable-default-scheduler-config可禁用默认配置回退(见 pkg/agentscheduler/scheduler.go)。

九、总结

Agent Scheduler 通过"独立进程 + 简化策略 + 即时调度 + 多 Worker 并发 + Binder 乐观并发控制"的组合,为 AI Agent 这类延迟敏感、任务高频创建的负载提供了快速路径调度能力;又通过与 Sharding Controller、NodeShard 的联动,实现了与 Volcano Scheduler 基于分片的并行协同调度,使不同特性的负载可以各得其所。本文涉及的调度队列、Binder 冲突处理与分片协调机制均有对应的源码实现(pkg/agentscheduler、pkg/controllers/sharding)与部署模板(installer/helm/chart/volcano)可供进一步深入研读;文档中标注 TBD 的 Snapshot 快速更新机制与 Agent Scheduler 详细配置部分,可关注仓库后续更新。

【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcano

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询