4. Scheduler 调度模型:调度队列、调度算法、预选与优选、绑定,CPU 密集型与内存缓存分析

Kubernetes Scheduler 是控制面中负责将 Pod 绑定到合适 Node 的核心组件。其调度过程并非一次性的随机选择,而是一个包含调度队列管理、调度算法循环(预选 & 优选)以及绑定的精密流水线。本章深入剖析该模型的内部机制,并重点分析其 CPU 密集型特征与内存缓存策略,为容量规划提供理论依据。

4.1 调度整体流程与核心组件

调度器的主循环通常被称为 Schedule One,每次为一个待调度的 Pod 执行完整的调度周期。该周期可抽象为以下四个阶段:

  1. 调度队列(Scheduling Queue):管理待调度的 Pod,支持优先级排序与重试。
  2. 预选(Predicates / Filtering):过滤掉不满足 Pod 运行要求的 Node。
  3. 优选(Priorities / Scoring):对通过预选的 Node 进行打分排序。
  4. 绑定(Binding):将 Pod 与最优 Node 的关联信息写入 API Server。
关键认知: 调度器是典型的 CPU 密集型 组件。预选与优选阶段涉及大量 Node 信息的遍历、比较与计算,而调度队列与缓存则依赖高效的内存数据结构来降低 API Server 的负载。
Scheduler 主循环流程 Scheduler 主循环:Schedule One 流程 调度队列 预选 (Filter) 优选 (Score) 绑定 阶段说明: • 调度队列:从 API Server Watch 机制接收 Pod,按优先级排序,支持重试与 backoff。 • 预选:遍历所有 Node,执行 Predicates(如端口冲突、资源不足、污点容忍)。 • 优选:对过滤后的 Node 执行 Priorities(如资源均衡、亲和性打分),选出最优。 • 绑定:异步将 Pod 与 Node 的绑定关系写入 etcd,触发 kubelet 创建容器。

4.2 调度队列:优先级与公平性

调度队列是调度器的入口,负责接收、排序和缓存待调度的 Pod。Kubernetes 使用 PriorityQueue 实现,内部维护三个子队列:

队列名称 数据结构 作用
activeQ 堆(Heap) 存放所有可立即调度的 Pod,按优先级排序。
backoffQ 堆(Heap) 存放调度失败的 Pod,按重试时间排序,到期后移回 activeQ。
unschedulableQ Map 存放因资源不足等不可调度原因失败的 Pod,当集群拓扑变化时重新评估。
性能要点: 调度队列的操作(入队、出队、排序)是 O(log n) 复杂度。在 Pod 数量巨大(如 10 万+)时,队列操作本身会成为 CPU 热点。此外,backoffQ 和 unschedulableQ 的频繁移动会加剧锁竞争。

4.3 预选与优选:调度算法的核心

调度算法循环是 CPU 消耗的主力。预选阶段需要遍历集群中所有 Node(默认开启 NodeResourcesFit、NodeName、PodToleratesNodeTaints 等内置 Predicates),优选阶段则对候选 Node 执行加权打分。

4.3.1 预选(Filtering)

预选阶段的核心是 并行化。调度器会启动多个 Goroutine 同时检查 Node,每个 Goroutine 执行一组 Predicates。常见的预选检查包括:

  • NodeResourcesFit:检查 Node 剩余 CPU、内存是否满足 Pod Request。
  • NodePorts:检查 Node 端口是否被占用。
  • PodToleratesNodeTaints:检查 Pod 是否容忍 Node 的 Taints。
  • MatchNodeSelector:检查 Node 标签是否匹配 Pod 的 nodeSelector。

4.3.2 优选(Scoring)

优选阶段对过滤后的 Node 进行打分,分数范围 0-100。调度器最终选择分数最高的 Node。常见的优选策略:

优选策略 权重 计算方式
NodeResourcesBalancedAllocation 1 CPU 与内存使用率越均衡,分数越高。
NodeResourcesLeastAllocated 1 剩余资源越多,分数越高。
ImageLocality 1 Node 上已有 Pod 所需镜像,分数越高。
InterPodAffinity 2 满足 Pod 亲和性/反亲和性规则。
容量规划警示: 优选阶段的计算复杂度与 候选 Node 数量 × 优选策略数量 成正比。当集群规模超过 5000 Node 时,优选阶段的 CPU 消耗会呈线性增长,建议启用 PercentageOfNodesToScore 参数来限制参与打分的 Node 比例(默认 50%)。

4.4 绑定:异步写入与乐观锁

绑定阶段将调度结果写入 API Server。调度器通过 Binder 接口向 API Server 发送 POST /api/v1/namespaces/{ns}/pods/{name}/binding 请求。该操作是异步的,不会阻塞调度主循环。

// 绑定请求的简化示例
{
  "apiVersion": "v1",
  "kind": "Binding",
  "metadata": {
    "name": "my-pod",
    "namespace": "default"
  },
  "target": {
    "apiVersion": "v1",
    "kind": "Node",
    "name": "node-01"
  }
}

绑定操作本身较轻量,但需要注意 乐观锁冲突:当多个调度器实例(或高并发场景下)同时绑定同一 Pod 时,API Server 会返回冲突错误,调度器需要重新入队并重试。

4.5 CPU 密集型与内存缓存分析

调度器的性能瓶颈主要集中在 CPU 和 内存 两个维度。理解其资源消耗模式是容量规划的前提。

4.5.1 CPU 密集型特征

调度器的 CPU 消耗主要来自:

  • 预选阶段的 Node 遍历:每个 Pod 调度都需要遍历所有 Node(或缓存快照),执行 Filter 函数。
  • 优选阶段的打分计算:对候选 Node 执行多个 Score 函数,涉及浮点运算与 Map 遍历。
  • 队列操作:堆的 Push/Pop 操作在 Pod 数量大时产生 CPU 开销。
  • Goroutine 调度:并行 Filter 和 Score 会创建大量 Goroutine,增加 Go 运行时调度压力。

4.5.2 内存缓存策略

为了减少对 API Server 的频繁调用,调度器维护了 Scheduler Cache,用于存储 Node 信息和 Pod 状态。该缓存是调度器性能优化的核心。

缓存组件 存储内容 更新机制
NodeInfo Node 的 CPU、内存、GPU 总量与已分配量 通过 Watch 事件增量更新
PodInfo 已调度 Pod 的 Request 与 Node 关联 通过 Watch 事件增量更新
ImageCache Node 上已存在的容器镜像列表 定期同步 + Watch
优化实践: 调度器缓存默认使用 LRU(Least Recently Used) 策略。在集群规模超过 3000 Node 时,建议将 --cache-size 参数调大(如 5000),避免缓存频繁驱逐导致性能抖动。同时,监控 scheduler_cache_size 指标,确保缓存命中率 > 99%。
Scheduler 内存缓存架构 Scheduler 内存缓存架构与数据流 API Server Watch Scheduler Cache NodeInfo Map PodInfo Map ImageCache (LRU) 读取 调度算法 (Filter & Score) 说明:调度算法不直接查询 API Server,而是从本地缓存读取 Node 和 Pod 快照,大幅降低 API Server 负载与网络延迟。

4.6 容量规划关键指标

针对 Scheduler 的容量规划,需要重点监控以下指标:

指标名称 类型 建议阈值 说明
scheduler_e2e_scheduling_duration_seconds Histogram P99 < 5s 端到端调度延迟,超过 5s 说明调度器过载。
scheduler_pod_scheduling_duration_seconds Histogram P99 < 2s 单个 Pod 的调度算法耗时。
scheduler_queue_incoming_pods_total Counter 无固定值 观察 Pod 入队速率,用于评估集群负载。
scheduler_cache_size Gauge 稳定 < 缓存上限 缓存条目数,持续增长可能触发 LRU 驱逐。
process_cpu_seconds_total Counter 单核利用率 < 80% 调度器进程 CPU 使用率,超过 80% 需扩容。
避坑指南: 不要将调度器与 API Server 部署在同一节点上。调度器的 CPU 密集型计算会与 API Server 的请求处理争抢 CPU 时间片,导致控制面整体响应变慢。建议为调度器预留 2-4 个独占 CPU 核心,并设置 --kube-api-qps=100 限制其对 API Server 的请求速率。

4.7 本章小结

Scheduler 的调度模型是一个精心设计的流水线:调度队列负责优先级管理,预选与优选负责 Node 筛选与打分,绑定负责结果持久化。其 CPU 密集型特征要求我们在容量规划时重点关注 调度延迟 和 缓存命中率。通过合理配置 PercentageOfNodesToScore、--cache-size 以及 CPU 资源限制,可以有效支撑大规模集群的调度性能。