3. 调度算法基础:Predicates算法、Priorities算法、调度队列

Kubernetes 调度器的核心工作是将待调度的 Pod 绑定到最合适的 Node 上。这一过程主要分为三个关键阶段:Predicates(预选)、Priorities(优选) 以及 调度队列(Scheduling Queue) 的管理。理解这三者的工作原理是分析调度器性能瓶颈的基石。

3.1 Predicates 算法:硬性过滤

Predicates 阶段是一组“硬约束”检查,用于过滤掉不满足 Pod 运行基本条件的 Node。只有通过所有 Predicates 检查的 Node 才会进入下一阶段。如果某个 Node 未通过任意一项检查,则立即被淘汰。

关键特性: Predicates 是“与”逻辑,所有检查必须全部通过。该阶段是调度器 CPU 消耗的主要来源之一,尤其是在大规模集群中。

3.1.1 常用 Predicates 算法

算法名称 检查内容 性能影响
PodFitsResources 检查 Node 剩余 CPU、内存是否满足 Pod 的 requests 高(需计算 Node 已分配资源)
PodFitsHostPorts 检查 Pod 请求的端口是否已被占用 低
PodSelectorMatches 检查 Node 的标签是否匹配 Pod 的 nodeSelector 低
NoDiskConflict 检查 Pod 请求的 Volume 是否与 Node 上已有挂载冲突 中
CheckNodeCondition 检查 Node 是否处于 Ready、DiskPressure 等正常状态 低
CheckVolumeBinding 检查 Pod 是否满足 PVC 的调度约束(动态绑定) 高(需与 API Server 交互)

3.1.2 Predicates 执行流程

调度器会遍历所有 Node,对每个 Node 依次执行上述检查。为了提高效率,调度器会优先执行计算量小、淘汰率高的检查(如 CheckNodeCondition),一旦失败则跳过后续检查。

// 伪代码示意
for node in allNodes:
    if not CheckNodeCondition(node):
        continue
    if not PodFitsResources(node, pod):
        continue
    if not PodFitsHostPorts(node, pod):
        continue
    // ... 其他检查
    feasibleNodes.append(node)

3.2 Priorities 算法:软性评分

Priorities 阶段对通过 Predicates 的 Node 进行“软约束”评分,最终选择得分最高的 Node 作为调度目标。该阶段决定了调度结果的“优劣”,其计算复杂度直接影响调度延迟。

3.2.1 常用 Priorities 算法

算法名称 评分依据 权重
LeastRequestedPriority 优先选择资源利用率低的 Node(CPU + 内存) 默认权重高
BalancedResourceAllocation 优先选择 CPU 和内存使用率最均衡的 Node 默认权重中
NodeAffinityPriority 根据 Pod 的 nodeAffinity 规则进行加权 用户可配置
InterPodAffinityPriority 根据 Pod 间的亲和/反亲和规则评分 高(计算复杂)
ImageLocalityPriority 优先选择已缓存 Pod 所需镜像的 Node 低
优化提示: 在集群规模较大时,InterPodAffinityPriority 和 NodeAffinityPriority 的评分计算会显著增加调度延迟。建议根据业务场景合理配置权重,或使用 scoreExtension 插件进行自定义优化。

3.3 调度队列:Pod 的等待与排序

调度队列是调度器的“输入缓冲区”。所有待调度的 Pod 首先进入队列,调度器按照特定顺序从队列中取出 Pod 进行调度。队列的管理策略直接影响调度的公平性和吞吐量。

3.3.1 队列结构与优先级

Kubernetes 调度队列是一个基于优先级的队列,内部包含三个子队列:

  • activeQ:存放等待调度的 Pod,按优先级排序。
  • backoffQ:存放调度失败的 Pod,经过退避时间后重新进入 activeQ。
  • unschedulableQ:存放因资源不足或节点不可用而无法调度的 Pod,等待集群状态变化后重新尝试。

3.3.2 队列操作流程

  1. 入队:新创建的 Pod 或经过重试的 Pod 进入 activeQ。
  2. 出队:调度器从 activeQ 头部取出优先级最高的 Pod。
  3. 失败处理:若调度失败,Pod 进入 backoffQ(可重试)或 unschedulableQ(等待事件触发)。
  4. 重试:backoffQ 中的 Pod 在退避时间后自动回到 activeQ。
性能瓶颈点: 当集群中存在大量高优先级 Pod 时,低优先级 Pod 可能长时间滞留在队列中,导致“饥饿”现象。此外,频繁的队列操作(如入队、出队、排序)在高并发场景下会消耗大量 CPU。

3.4 调度算法整体流程 SVG 图

下图展示了从 Pod 入队到最终绑定的完整调度算法流程,清晰呈现 Predicates、Priorities 与调度队列的协作关系。

K8s 调度算法整体流程 调度算法整体流程 调度队列 activeQ (优先级排序) backoffQ (退避重试) unschedulableQ Predicates 阶段 PodFitsResources PodFitsHostPorts CheckNodeCondition Priorities 阶段 LeastRequested NodeAffinity InterPodAffinity 绑定到最优 Node 调度失败处理 说明: 1. Pod 从调度队列出队后,依次经过 Predicates 和 Priorities 阶段。 2. Predicates 失败则直接进入失败处理队列(backoffQ / unschedulableQ),等待重试。

3.5 调度队列状态转换 SVG 图

下图详细展示了 Pod 在调度队列内部的三种状态转换路径,帮助理解调度失败后的重试机制。

调度队列状态转换 调度队列状态转换 activeQ 等待调度 backoffQ 退避重试 unschedulableQ 等待事件触发 调度器 调度失败 退避结束 资源不足 集群事件(新增 Node / 资源释放)

3.6 性能优化要点总结

  • Predicates 优化:优先执行轻量级检查,减少不必要的资源计算;利用 nodeAffinity 和 taintToleration 提前缩小候选 Node 范围。
  • Priorities 优化:合理配置评分权重,避免高复杂度算法(如 InterPodAffinity)成为瓶颈;考虑使用 scoreExtension 插件进行并行评分。
  • 调度队列优化:监控队列长度和 Pod 等待时间;调整 backoffQ 的退避参数,避免频繁重试;使用 unschedulableQ 的事件驱动机制减少无效调度。