AIGC标识 [AI生成] kube-scheduler核心优化总结

一、整体架构演进

kube-scheduler 从早期的单体调度器演进到基于 Scheduler Framework 的插件化架构,核心优化思路围绕减少锁竞争提升缓存命中率并行化调度降低无效调度四个方向展开。

1.1 调度流程概览

Pod 进入调度队列
    ↓
  出队(Pop)
    ↓
  调度循环(Scheduling Cycle)
    ├── PreFilter(前置过滤)
    ├── Filter(节点过滤/预选)
    ├── PostFilter(后置过滤/抢占)
    ├── PreScore(前置打分)
    ├── Score(节点打分/优选)
    ├── Reserve(预留资源)
    └── Permit(许可)
    ↓
  绑定循环(Binding Cycle)
    ├── WaitOnPermit(等待许可)
    ├── PreBind(前置绑定)
    ├── Bind(绑定)
    └── PostBind(后置绑定)

1.2 两个独立控制循环

kube-scheduler 内部有两个独立的控制循环:

  • 调度循环(Scheduling Loop):不断从队列中取出 Pod,为其选择最合适的节点。
  • 节点/集群信息更新循环:通过 informer 监听 Node、Pod 等资源变化,实时更新调度缓存。

两个循环通过 scheduler cache 解耦,调度循环只读缓存,更新循环写缓存,避免了频繁的锁竞争。


二、调度队列优化

2.1 三种队列设计

kube-scheduler 维护三个 Pod 队列,各司其职:

队列 作用 数据结构
activeQ(活跃队列) 存放等待调度的 Pod,按优先级排序 堆(Heap)
backoffQ(退避队列) 存放调度失败后等待重试的 Pod,指数退避 堆(Heap)
unschedulableQ(不可调度队列) 存放完全不可调度的 Pod,等待集群变化后重新入队 Map + 双向链表

2.2 Queue Hint(队列提示)

引入版本:Kubernetes v1.28 开始逐步引入,v1.30+ 逐步成熟。

核心思想:传统方式下,任何集群变化(如节点新增、Pod 删除等)都会将 unschedulableQ 中的所有 Pod 全部移回 activeQ 重试,造成大量无效调度。Queue Hint 让每个 Filter 插件告诉调度器:哪些变化会影响我对 Pod 的调度决策,从而只移动真正可能调度成功的 Pod。

工作机制

// 每个 Filter 插件可以实现 EventsToRegister 方法
type FilterPlugin interface {
    Filter(ctx context.Context, state *CycleState, pod *v1.Pod, nodeInfo *NodeInfo) *Status
    EventsToRegister() []ClusterEvent
}
  • 每个插件声明自己关心的集群事件类型(如 NodeAdd、PodUpdate 等)
  • 当集群发生变化时,调度器只唤醒那些受该变化影响的 Pod
  • 大幅减少 unschedulableQ → activeQ 的无效搬迁

收益:在大规模集群中,unschedulable Pod 数量巨大时,Queue Hint 能显著降低调度器负载,提升调度吞吐量。

2.3 队列间 Pod 倒换机制

Node 增加 / Pod 删除 / 资源变化等事件
        ↓
unschedulableQ 中受影响的 Pod(Queue Hint 过滤)
        ↓
  根据是否在退避期决定:
    ├── 退避期内 → backoffQ
    └── 退避期外 → activeQ
        ↓
  backoffQ 到期后自动移入 activeQ

三、调度缓存优化

3.1 Snapshot 快照机制

调度循环开始时,会从 scheduler cache 中 snapshot(拍快照),得到一份当前集群状态的只读副本。后续整个调度过程(Filter、Score 等)都基于这份快照进行,不再访问共享缓存。

优势

  • 无锁读取:调度过程中不需要加锁,大幅减少锁竞争
  • 一致性:单次调度内看到的集群状态是一致的
  • 并行安全:多个调度协程可以并行工作,各自持有自己的快照

3.2 缓存分层设计

schedulerCache
    ├── Node 缓存(节点信息、已分配资源)
    ├── Pod 缓存(已调度 Pod 的资源占用)
    ├── Assume 机制(预占缓存)
    └── Snapshot(只读快照)

3.3 Assume 机制

Pod 调度成功后,在真正 Bind 之前,先在缓存中 Assume(假设) 该 Pod 已经绑定到节点上,更新节点的已分配资源。这样后续调度能立即感知到该节点资源变化,不需要等待 API Server 的回调。

如果后续 Bind 失败,会调用 Forget 回滚 Assume 的结果。


四、预选(Filter)优化

4.1 并行化 Filter

对多个节点的 Filter 检查是并行执行的,利用多核 CPU 提升预选速度:

// 并行对所有节点执行 Filter
workqueue.ParallelizeUntil(ctx, 16, int(allNodes), checkNode)

默认并发度是 16parallelism 参数),可通过配置调整。

4.2 节点短路(Short-circuit)

  • 一旦某个 Filter 插件判定节点不通过,后续 Filter 不再执行
  • 按固定顺序执行 Filter,计算量小的前置,快速排除不合格节点
  • 节点数量较多时,采用 nominatedNode 优先检查机制

4.3 预选节点数量优化(percentageOfNodesToScore)

大规模集群中,不需要对所有节点都执行完整的预选+优选流程。调度器找到一定比例的可调度节点后就停止预选,直接进入优选阶段。

  • 默认策略:动态计算,节点越多,预选比例越低
  • 100 节点以下:100%(全量预选)
  • 5000 节点时:约 10%(500 个节点)
  • 可通过 percentageOfNodesToScore 配置项调整

目的:在保证调度质量的前提下,减少不必要的计算。


五、优选(Score)优化

5.1 并行化 Score

与 Filter 类似,对多个节点的 Score 计算也是并行执行的。

5.2 归一化打分

每个 Score 插件输出的分数范围不同(有的 0-10,有的 0-100),调度器会将其归一化到 0-100 的统一区间,然后按权重加权求和。

// 归一化公式
normalizedScore = int64(score) * int64(MaxNodeScore) / int64(maxScore)

5.3 常用打分插件及其权重

插件 默认权重 作用
NodeResourcesBalancedAllocation 1 资源均衡度
NodeResourcesFit 1 资源匹配度(支持 LeastAllocated / MostAllocated)
PodTopologySpread 2 Pod 拓扑分布
InterPodAffinity 2 Pod 间亲和/反亲和
NodeAffinity 1 节点亲和性
TaintToleration 1 污点容忍
ImageLocality 1 镜像本地性

六、Scheduler Framework 插件化

6.1 扩展点一览

Scheduler Framework 定义了多个扩展点,开发者可以通过实现插件接口来自定义调度逻辑,无需修改内核代码。

扩展点 阶段 说明
QueueSort 队列排序 决定 Pod 在 activeQ 中的排序
PreFilter 前置过滤 计算 Pod 级别的元信息,供后续 Filter 使用
Filter 节点过滤 判断节点是否满足 Pod 要求
PostFilter 后置过滤 调度失败后执行,如抢占、降级
PreScore 前置打分 计算打分所需的公共信息
Score 节点打分 为可调度节点打分排序
Reserve 资源预留 Assume Pod 到节点前调用
Permit 许可 批准/拒绝/延迟 Pod 的绑定
PreBind 前置绑定 绑定前执行额外操作
Bind 绑定 执行实际的绑定操作
PostBind 后置绑定 绑定成功后调用
Unreserve 预留回滚 绑定失败时回滚 Reserve 操作

6.2 多配置文件(Multi-profile)

kube-scheduler 支持同时运行多个调度配置文件(profile),每个 profile 可以:

  • 有独立的插件列表和配置
  • 有独立的调度队列
  • 有独立的调度循环

不同类型的 Pod 可以选择不同的 schedulerName,走不同的调度逻辑,互不影响。


七、抢占(Preemption)优化

7.1 抢占流程

当高优先级 Pod 无法调度时,触发抢占逻辑:

  1. 选出所有可能的候选节点
  2. 计算每个节点上需要驱逐的低优先级 Pod
  3. 选择代价最小的节点(驱逐 Pod 最少、优先级最低等)
  4. 驱逐选定的 Pod,将高优先级 Pod 调度上去

7.2 抢占优化点

  • 候选节点筛选:只考虑有低优先级 Pod 的节点
  • dry-run 抢占:在缓存中模拟抢占,不实际驱逐 Pod
  • nominatedNodeName:抢占成功后标记候选节点,下次优先调度

八、性能调优参数

8.1 关键配置项

参数 默认值 说明
kube-api-burst 100 API Server 请求突发量
kube-api-qps 50 API Server 请求 QPS
percentageOfNodesToScore 0(动态计算) 参与优选的节点比例
schedulerName default-scheduler 调度器名称
workers 数量 = CPU 核数 并行调度协程数

8.2 大规模集群建议

  1. 调高 workers:多核机器上增加并行调度协程数
  2. 降低 percentageOfNodesToScore:集群很大时(>1000 节点),适当降低预选节点比例
  3. 启用 Queue Hint:v1.28+ 启用,减少无效重调度
  4. 合理配置插件权重:根据业务场景调整,减少不必要的复杂计算
  5. 分层调度:使用多 profile,不同业务走不同调度逻辑

九、核心优化总结

优化方向 技术手段 收益
减少锁竞争 Snapshot 快照、调度循环只读缓存 调度过程无锁,吞吐提升
并行化 Filter/Score 并行执行、多 workers 利用多核,缩短单次调度时间
降低无效调度 Queue Hint、percentageOfNodesToScore 减少不必要的计算和重调度
插件化架构 Scheduler Framework、多 profile 灵活扩展,不修改内核
缓存优化 Assume 机制、分层缓存 实时感知资源变化,减少 API 调用
智能重调度 backoff 退避、unschedulableQ 分级 避免失败 Pod 频繁重试

kube-scheduler 的优化思路本质上是经典的空间换时间(缓存、快照)、并行化(多核利用)和减少无效计算(Hint、短路)三大范式在调度场景下的具体实践。

posted on 2026-07-11 12:23  王景迁  阅读(3)  评论(0)    收藏  举报

导航