Skip to main content

1. 资源抢占的背景和用途

1.1 什么是资源抢占

Kubernetes集群中,资源抢占(Preemption)是指当高优先级的工作负载需要资源但集群资源不足时,调度系统会终止低优先级的工作负载以释放资源,从而确保高优先级工作负载能够正常运行的机制。

资源抢占是解决资源竞争问题的关键技术,特别是在以下场景中尤为重要:

  • 资源紧张环境:在计算资源有限的集群中,需要确保关键业务获得足够资源
  • 混合负载场景:同一集群中同时运行在线服务批处理作业时,需要保证在线服务的资源优先级
  • 弹性计算:在需求波动较大的环境中,通过优先级机制实现资源的动态分配
  • 多租户环境:在多用户共享集群的情况下,通过优先级和抢占机制实现资源隔离和公平分配

1.2 Kubernetes原生抢占机制的局限性

Kubernetes原生的抢占机制主要基于Pod级别的PriorityClass实现,虽然提供了基本的资源抢占能力,但在复杂的高性能计算和AI/ML工作负载场景中存在以下局限性:

  1. 层级抢占机制不完善

    • 虽然原生的Job可以通过PriorityClass设置优先级,但缺乏队列级别的资源管理
    • 无法实现多层级、多维度的资源抢占策略
  2. 缺乏作业感知

    • 无法识别同一作业中不同Pod之间的关联关系
    • 在资源紧张时,可能导致需要同时运行的Pod无法同时获得资源(资源死锁,缺乏Gang调度)
    • 造成资源碎片化,降低资源利用效率
  3. 抢占策略单一

    • 仅支持基于优先级的简单抢占
    • 无法根据不同场景和业务需求定制复杂的抢占策略
  4. 多租户支持有限

    • 缺乏队列级资源保障和隔离机制
    • 难以为不同部门或团队提供差异化的资源配额和服务质量保障

1.3 Volcano抢占机制的优势

Volcano作为一个面向高性能计算和AI/ML工作负载的调度系统,提供了更加完善的资源抢占机制:

  1. 多层级抢占:支持Queue(队列)、Job(作业)和Pod(容器组)三个层级的资源抢占
  2. 作业感知:理解批处理作业的特性,支持Gang调度等高级特性
  3. 丰富的抢占策略:提供多种可配置的抢占策略,满足不同场景需求
  4. 队列级资源管理:支持队列级别的资源分配和抢占,适合多租户环境
  5. 公平性保障:通过DRF(主导资源公平)算法等机制,确保资源分配的公平性

2. Volcano资源抢占的设计与实现

Volcano的资源抢占机制设计为三个层级:Queue(队列)、Job(作业)和Pod(容器组),形成了一个层级分明的抢占体系。

2.1 Queue级别抢占

2.1.1 设计原理

QueueVolcano中最高层级的资源管理单位,比如在业务上可以代表一个租户或一个业务线。Queue级别的抢占主要基于以下原则:

  1. 优先级机制:每个Queue可以设置优先级(priority),高优先级Queue可以抢占低优先级Queue的资源。
  2. 资源配额Queue可以设置最小保障资源(guarantee)和最大资源上限(capacity)
  3. 权重分配:当多个Queue优先级相同时,可以通过权重(weight)决定资源分配比例和抢占顺序

注意事项:

  • Queue级别的抢占机制从Volcano v1.10.0版本开始支持。
  • Queue并不支持PriorityClass,而是通过priority属性来设置优先级。
  • 低优先级的Queue如果显式设置了reclaimable: false,那么该Queue不能被高优先级Queue抢占(reclaimable默认值为true)。
  • 不同资源管理插件(proportioncapacity)会影响资源的分配和抢占:
    • proportion插件会根据Queueweight属性决定资源分配比例和抢占顺序。每个队列的deserved资源 = 剩余资源 × (队列weight / 总weight)
    • capacity插件会根据Queuedeserved属性决定资源分配比例和抢占顺序。当priority相同时,按照allocated/deserved的比率排序。

2.1.2 实现方式

Volcano主要通过以下核心组件实现Queue级别的资源抢占:

  1. reclaim action:资源回收动作,是实现不同队列间资源抢占的核心机制

  2. 队列priority属性:在Queue定义中设置的优先级值,决定了队列间的抢占顺序

    下面是Volcano调度器的配置示例,展示了资源抢占相关的动作:

    # volcano-scheduler-configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: volcano-scheduler-config
    namespace: volcano-system
    data:
    volcano-scheduler.conf: |
    # 调度器执行的动作序列,包含资源回收和抢占动作
    actions: "enqueue, allocate, preempt, reclaim, backfill"
    # 其他插件配置...

    上述配置中,资源抢占相关的核心动作是reclaim。使用示例如下:

    apiVersion: scheduling.volcano.sh/v1beta1
    kind: Queue
    metadata:
    name: high-priority-queue
    spec:
    weight: 10
    capability:
    cpu: 100
    memory: 100Gi
    reclaimable: true # 允许其他Queue抢占此Queue的资源
    priority: 100 # 队列优先级,值越大优先级越高

2.2 Job级别抢占

2.2.1 设计原理

Job代表一个完整的工作单元,如一个AI训练任务或批处理作业。Job级别的抢占主要基于以下原则:

  1. 优先级机制

    • Job通过priorityClassName字段关联到KubernetesPriorityClass资源
    • 高优先级Job可以抢占同一Queue中低优先级Job的资源
    • Job的优先级会传递给其创建的所有Pod,除非Pod模板中明确指定了不同的priorityClassName
  2. 最小资源保障

    • Job可以设置minResources确保获得最小资源保障
    • 结合minAvailable参数确保关键任务的资源需求
  3. Gang调度

    • 支持All-or-Nothing的调度模式
    • 确保作业所有关键任务同时调度,避免资源碎片化

2.2.2 实现方式

Volcano主要通过以下核心组件实现Job级别的抢占:

  1. preempt action:资源抢占动作,是实现同一队列内不同作业间资源抢占的核心机制

  2. priorityClassName:与Job关联的优先级类,决定了作业间的抢占顺序

    apiVersion: batch.volcano.sh/v1alpha1
    kind: Job
    metadata:
    name: high-priority-job
    spec:
    minAvailable: 3
    priorityClassName: high-priority # 关联PriorityClass设置作业优先级
    queue: research # 指定所属队列
    tasks:
    - replicas: 3
    name: worker
    template:
    spec:
    containers:
    - image: training-image
    name: worker

2.3 Pod级别抢占

2.3.1 设计原理

PodKubernetes中最小的调度单位,也是Volcano调度的基本单位。Pod级别的抢占主要基于以下原则:

  1. 优先级机制Pod可以通过PriorityClasstask-priority注解设置优先级
  2. 可抢占性Pod可以通过volcano.sh/preemptable注解标记是否可被抢占
  3. 资源需求Pod的资源请求(requests)决定了需要多少资源

2.3.2 实现方式

Volcano主要通过以下核心组件实现Pod级别的抢占:

  1. priorityClassName属性:当Pod使用Volcano调度器时,priorityClassName的优先级影响范围取决于Pod所属的JobQueue

    • 如果Pod属于某个Volcano Job,其priorityClassName优先级仅在同一个Queue内的不同Job之间生效。
    • 如果Pod不属于任何Volcano Job,其priorityClassName优先级在整个集群范围内生效(不管该Pod是否属于某个Queue)。
    • 优先级值越大,Pod的优先级越高,在资源竞争时优先获得资源。
  2. volcano.sh/task-priority注解:设置同一Job内不同Pod的优先级,是实现Pod间抢占的核心

  3. volcano.sh/preemptable注解:标记Pod是否可被抢占,控制Pod的可抢占性,即便PodpriorityClassName优先级较低,只要没有设置volcano.sh/preemptable注解为true,就不能被高优先级的Pod抢占。

    apiVersion: v1
    kind: Pod
    metadata:
    name: high-priority-pod
    annotations:
    volcano.sh/task-priority: "10" # 设置Pod在Job内的优先级
    volcano.sh/preemptable: "true" # 标记Pod可被抢占
    spec:
    priorityClassName: high-priority # 设置Pod的全局优先级
    schedulerName: volcano # 使用Volcano调度器

3. 资源抢占的层级关系

Volcano的抢占体系中,QueueJobPod三个层级之间存在明确的优先级关系,形成了一个层级化的抢占机制。

3.1 QueueQueue之间的抢占

当集群资源紧张时,Queue之间的抢占遵循以下规则:

  1. 优先级决定性:高优先级Queue可以抢占低优先级Queue的资源(priority属性)
  2. 权重影响:当优先级相同时,权重(weight属性)较高的Queue可以获得更多资源
  3. 最小保障:每个Queueguarantee资源是受保护的,不会被抢占
  4. 资源回收:当高优先级Queue不需要资源时,被抢占的Queue可以重新获得资源
  5. 可回收标识:设置了reclaimable: true或者没有设置reclaimable属性(默认值为true)的Queue才能被高优先级Queue抢占资源。如果Queuereclaimable属性设置为false,即使其优先级较低,也不会被高优先级Queue抢占资源。

抢占过程:

  1. Volcano调度器检测到高优先级Queue资源不足
  2. 根据优先级和权重策略选择低优先级的Queue
  3. 检查低优先级Queuereclaimable属性,只有设置为trueQueue才能被抢占
  4. 从可抢占的低优先级Queue中选择可抢占的JobPod
  5. 驱逐选中的Pod,释放资源给高优先级Queue

3.2 JobJob之间的抢占

在同一Queue内,Job之间的抢占遵循以下规则:

  1. 优先级决定性:高优先级Job可以抢占低优先级Job的资源
  2. 创建时间:当优先级相同时,通常先创建的Job优先级更高
  3. 最小资源:每个JobminAvailable资源需求会影响抢占决策
  4. Gang调度:支持All-or-Nothing的调度模式,确保作业完整性

抢占过程:

  1. Volcano检测到高优先级Job资源不足
  2. 根据PriorityClass和创建时间选择同一Queue中优先级较低的Job
  3. 从低优先级Job中选择可抢占的Pod
  4. 驱逐选中的Pod,释放资源给高优先级Job

3.3 PodPod之间的抢占

在同一Job内,Pod之间的抢占遵循以下规则:

  1. task-priority决定性:高task-priorityPod可以抢占低task-priorityPod
  2. 可抢占性:只有标记为可抢占(volcano.sh/preemptable: "true"注解)的Pod才能被抢占
  3. BestEffort限制BestEffort Pod不能抢占非BestEffort PodBestEffort Pod是没有明确设置资源请求requests和限制limitsPod,在资源紧张时是最先被终止的)。
  4. 状态限制:只有处于Running状态的Pod才能被抢占

抢占过程:

  1. Volcano检测到高优先级Pod无法调度
  2. 根据任务优先级找到同一Job中优先级较低的Pod
  3. 检查Pod的可抢占性和其他约束条件
  4. 驱逐选中的Pod,释放资源给高优先级Pod

3.4 跨层级抢占的优先顺序

当涉及跨层级的资源抢占时,Volcano遵循以下优先顺序:

  1. Queue优先级最高:不同Queue之间的优先级高于Queue内部的Job优先级
  2. Job优先级次之:同一Queue内不同Job之间的优先级高于Job内部的Pod优先级
  3. Pod优先级最低:同一Job内不同Pod之间的优先级最低

这意味着:

  • 即使是低优先级Queue中的高优先级Job,也无法抢占高优先级Queue中的低优先级Job
  • 即使是低优先级Job中的高优先级Pod,也无法抢占高优先级Job中的低优先级Pod
  • 这种设计确保了资源抢占的层次性和可预测性

这种分层优先级设计的优势:

  1. 资源隔离:确保高优先级Queue的资源不会被低优先级Queue抢占
  2. 可预测性:资源抢占行为更加可预测,便于资源规划
  3. 业务保障:重要业务可以通过Queue优先级得到保障
  4. 灵活性:在保证优先级层次的同时,仍然允许同层级的资源抢占

使用建议:

  1. 根据业务重要性设置合适的Queue优先级
  2. Queue内部,根据任务紧急程度设置Job优先级
  3. Job内部,根据任务依赖关系设置Pod优先级
  4. 合理使用Queue reclaimable属性和Pod volcano.sh/preemptable注解,进一步控制资源抢占行为