Scheduler之Queue 组件

在 Kubernetes 中,Scheduler 的 Queue 组件是调度流程的核心模块之一,负责高效管理待调度的 Pod,确保调度器的性能和可靠性。以下是其关键设计和工作原理的详细分析:


1. Queue 的作用

Queue 的主要职责是 临时存储待调度的 Pod,并为调度器提供以下能力:

  • 事件缓冲:接收来自 API Server 的 Pod 事件(如新增、更新),避免直接处理高频率事件。
  • 优先级调度:支持按优先级(如 PriorityClass)或其他策略排序 Pod。
  • 重试机制:处理调度失败的 Pod,支持延迟重试。
  • 并发控制:协调多个调度线程(Workers)从队列中安全消费 Pod。

2. Queue 的核心实现

Kubernetes 调度器默认使用 PriorityQueue(优先级队列),其内部结构分为多个子队列以实现复杂逻辑:

子队列类型

  1. ActiveQ(Active Queue)

    • 存储所有 待调度的 Pod(包括首次调度和需要重试的 Pod)。
    • 默认按 Pod 的优先级(PriorityClass)排序,高优先级 Pod 优先出队。
  2. BackoffQ(退避队列)

    • 存储 调度失败 且需要延迟重试的 Pod。
    • 采用指数退避策略(Exponential Backoff),避免频繁重试失败 Pod 导致性能问题。
    • 退避时间到期后,Pod 会被移回 ActiveQ
  3. UnschedulablePods

    • 存储被标记为 暂时不可调度 的 Pod(如因资源不足、节点亲和性冲突等)。
    • 这些 Pod 会周期性地(或通过事件触发)被重新评估,若条件满足则移回 ActiveQ

关键数据结构

  • 堆(Heap)ActiveQBackoffQ 通常基于堆实现,保证优先级排序的高效性(插入和取出操作复杂度为 O(log n))。
  • 定时器(Timer):用于管理 BackoffQ 中 Pod 的延迟重试时间。

3. Queue 的工作流程

Pod 入队(Enqueue)

  1. 新增 Pod
    • 通过 Watch API Server 监听到 ADDED 事件(如新创建的 Pod) → 直接加入 ActiveQ
  2. 更新 Pod
    • 若 Pod 因调度失败被更新(如 Unschedulable 状态) → 根据条件进入 BackoffQUnschedulablePods
  3. 外部触发
    • 集群状态变更(如新增节点)时,会扫描 UnschedulablePods,尝试将符合条件的 Pod 移回 ActiveQ

Pod 出队(Dequeue)

  1. 调度器的 Worker 线程从 ActiveQ 头部取出最高优先级的 Pod。
  2. ActiveQ 为空,则检查 BackoffQ 中是否有已到期的 Pod,将其移入 ActiveQ

4. 关键特性

优先级与公平性

  • 优先级排序:基于 spec.priority(PodPriority),确保高优先级任务优先调度。
  • 公平性:相同优先级的 Pod 按 FIFO 处理,避免饿死。

退避策略

  • 初始退避时间(如 1s),失败后指数增长(如 2s, 4s, 8s…),直到最大限制(如 10s)。
  • 避免因持续重试不可调度的 Pod 浪费资源。

事件驱动优化

  • 通过 Informer 监听集群事件(如节点资源释放),主动唤醒 UnschedulablePods 的重新评估。

5. 源码中的核心逻辑

(以 Kubernetes 代码库为例)

  • PriorityQueue 定义
    pkg/scheduler/internal/queue/scheduling_queue.go
    type PriorityQueue struct {
        activeQ       *heap.Heap            // 活跃队列(按优先级排序)
        podBackoffQ   *heap.Heap            // 退避队列
        unschedulableQ *UnschedulablePodsMap // 不可调度 Pod 的缓存
        ...
    }
    
  • Pod 入队逻辑
    func (p *PriorityQueue) Add(pod *v1.Pod) error {
        if p.unschedulableQ.Get(pod) != nil {
            // 从不可调度队列移到 ActiveQ
            p.activeQ.Add(pod)
        } else {
            // 新 Pod 直接加入 ActiveQ
            p.activeQ.Add(pod)
        }
    }
    

6. 性能优化实践

  • 批量处理:合并短时间内的事件,减少频繁锁竞争。
  • 本地缓存:通过 Informer 的本地缓存减少 API Server 负载。
  • 并行化:多个 Worker 并发消费 ActiveQ,提升吞吐量。

总结

Scheduler 的 Queue 组件通过 多级子队列(ActiveQ/BackoffQ/UnschedulablePods)优先级策略,实现了高效、可靠的 Pod 调度管理。其设计平衡了实时性、公平性和容错性,是 Kubernetes 调度器高性能的关键保障。

posted on 2025-05-07 18:49  Leo-Yide  阅读(54)  评论(0)    收藏  举报