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 队列操作流程
- 入队:新创建的 Pod 或经过重试的 Pod 进入 activeQ。
- 出队:调度器从 activeQ 头部取出优先级最高的 Pod。
- 失败处理:若调度失败,Pod 进入 backoffQ(可重试)或 unschedulableQ(等待事件触发)。
- 重试:backoffQ 中的 Pod 在退避时间后自动回到 activeQ。
性能瓶颈点: 当集群中存在大量高优先级 Pod 时,低优先级 Pod 可能长时间滞留在队列中,导致“饥饿”现象。此外,频繁的队列操作(如入队、出队、排序)在高并发场景下会消耗大量 CPU。
3.4 调度算法整体流程 SVG 图
下图展示了从 Pod 入队到最终绑定的完整调度算法流程,清晰呈现 Predicates、Priorities 与调度队列的协作关系。
3.5 调度队列状态转换 SVG 图
下图详细展示了 Pod 在调度队列内部的三种状态转换路径,帮助理解调度失败后的重试机制。
3.6 性能优化要点总结
- Predicates 优化:优先执行轻量级检查,减少不必要的资源计算;利用
nodeAffinity和taintToleration提前缩小候选 Node 范围。 - Priorities 优化:合理配置评分权重,避免高复杂度算法(如 InterPodAffinity)成为瓶颈;考虑使用
scoreExtension插件进行并行评分。 - 调度队列优化:监控队列长度和 Pod 等待时间;调整
backoffQ的退避参数,避免频繁重试;使用unschedulableQ的事件驱动机制减少无效调度。