多维组调度(Gang)
背景信息
组调度(Gang)满足了调度过程中“All or nothing”的调度需求,避免Pod的任意调度导致集群资源的浪费,主要应用于AI、大数据等多任务协作场景。启用该能力后,可以解决分布式训练任务之间的资源忙等待和死锁等痛点问题,大幅度提升整体训练性能。
随着AI任务的演进,AI任务可以进一步细分为不同维度的子任务,例如分布式训练任务中的多个分片或分布式推理任务中的不同Role。子任务内部及子任务之间出现了新的多维度Pod组调度(Gang)需求。子任务内的多个Pod需在最小资源得到满足后才能启动,以防止子任务内部只有部分Pod启动而导致任务无效运行。当存在多个子任务时,需确保一定数量或一定比例的子任务启动后,任务才能正常运行。为此,Volcano提供了多维组调度(Gang)能力策略,在调度时为不同维度的任务提供组调度(Gang)能力,以满足不同维度任务对资源整体调度的需求。
功能介绍
多维组调度(Gang)支持以下能力:
- 任务维度组调度(Gang)能力
指在调度过程中检查任务下的Pod已调度数量是否达到了最小运行数量。只有当任务内的最小Pod运行数量得到满足时,该任务下的Pod才会被调度到集群中,否则任务调度将不会执行。
- 子任务维度组调度(Gang)能力
每个子任务需遵循组调度(Gang)原则。只有当一个子任务内的所有Pod均满足Gang调度条件时,该子任务才会被调度,否则该子任务的调度将不会执行。在集群资源不足的情况下,确保子任务能够整体调度,以保持子任务的完整性,避免因Pod数量不足而导致子任务无效运行,从而浪费资源。
- 子任务之间组调度(Gang)能力
在调度过程中,监控任务中不同类型的子任务可调度数量,当最小可调度子任务数量要求得到满足时,该任务下的Pod才会被调度;否则,任务调度将不会执行。当集群资源不足时,允许以子任务为单位进行弹性调度,确保任务内启动的不同类型子任务满足最低部署数量和比例要求,以保障任务的有效运行。
Volcano通过PodGroup提供了对任务内部Pod的分组定义,通过配置字段将一个PodGroup内的Pod分成多个SubGroup。在此过程中,可以定义每个SubGroup进行组调度(Gang)的Pod数量以及不同类型SubGroup的最小数量要求。在调度时,每个SubGroup将会遵循各自的组调度条件约束。任务负载可以通过设置关联的PodGroup,利用Volcano对负载进行多维Gang调度。
apiVersion: scheduling.volcano.sh/v1beta1
kind: PodGroup
metadata:
name: pg-test1
namespace: default
spec:
subGroupPolicy:
- name: subgroup-test
subGroupSize: 2 # 指示subGroup内至少需要几个Pods可被调度
minSubGroups: 4 # 指示至少需要多少subGroup可被调度
labelSelector: # 分组Pod需要匹配的标签
matchLabels:
task-type: test
matchLabelKeys: # Pod的分组依据,Label value值相同的Pod分到同一个SubGroup中
- group
minMember: 8 #PodGroup内至少需要几个Pods可被调度 涉及参数解释如下:
- minMember:指定工作负载最小Pod数量。
- subGroupPolicy: 指定分组策略,将任务中的Pod按照策略分为不同的分组。
- name:分组策略名字。
- subGroupSize: 指定一个分组里面最小Pod的数量。
- minSubGroups:指定当前分组策略内最小的分组数量。
- labelSelector:被分组的Pod需要匹配的标签。
- matchLabelKeys:Pod的分组依据,根据Pod标签所对应的value值进行分组,value值相同的Pod分到同一个SubGroup中。
Volcano Job在Job定义中提供了对应的分组定义和组调度(Gang)约束定义,通过Volcano自动创建和管理PodGroup,并在调度时根据多维Gang调度策略对Volcano Job进行调度。
前提条件
集群中已安装Volcano调度器插件,且插件版本在1.21.1及以上。
配置组调度策略
安装Volcano后,您可通过“配置中心 > 调度配置”选择开启或关闭Gang调度能力,默认开启。
- 登录CCE控制台,单击集群名称进入集群。
- 在左侧选择“配置中心”,在右侧选择“调度配置”页签。
- 选择Volcano调度器,在“AI任务性能增强调度”配置中,选择是否开启“组调度 (Gang) ”。
启用该能力后,可增强集群业务的吞吐量,提高业务运行性能。
- 修改完成后,单击“确认配置”。
配置完成后,可以在工作负载或Volcano Job中使用Gang调度能力。
部署负载使用多维组调度(Gang)能力
本文通过以下场景示例为您介绍如何使用多维组调度(Gang)能力。
创建Volcano Job
通过Volcano Job创建训练任务负载时,可以通过Volcano Job定义不同的训练分片Gang调度策略,实现不同维度的弹性部署。在指定训练任务整体Pods数量的基础上,通过partitionPolicy指定任务内不同分片的分组策略及分片的最少启动数量,确保调度时分片Pod和分片的整体调度。创建Volcano Job时,只需指定minAvailable数量和partitionPolicy即可,Volcano调度器会根据partitionPolicy自动创建并管理PodGroup的分组,示例如下。
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: sample
spec:
schedulerName: volcano
minAvailable: 5 # 可选,表示Job内最小Pod数量(Gang调度条件)
tasks:
- name: "ps"
replicas: 2 # 必选,表示一个任务内有多少Pod
partitionPolicy: # 可选,表示对当前任务内的所有Pod进行分组
totalPartitions: 2 # 必选,对任务内的一组Pod分为多少组
partitionSize: 1 # 必选,每组中包含的Pod数量(Gang调度条件),totalPartitions和partitionSize相乘的结果应与replicas相等
minPartitions: 1 # 可选,表示分组数量的Gang调度条件
template:
spec:
containers:
- image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
imagePullPolicy: IfNotPresent
name: ps
resources:
requests:
cpu: "500m"
restartPolicy: OnFailure
- name: "worker"
replicas: 8 # 必选,表示一个任务内有多少Pod
partitionPolicy: # 可选,表示对当前任务内的所有Pod进行分组,按照分组设置网络拓扑亲和的调度能力
totalPartitions: 4 # 必选,对task内的一组Pod分为多少组
partitionSize: 2 # 必选,每组中包含的pod数量,totalPartitions和partitionSize相乘的结果应与replicas相等
minPartitions: 2 # 可选,表示分组数量的gang调度条件
template:
spec:
containers:
- image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
imagePullPolicy: IfNotPresent
name: worker
resources:
requests:
cpu: "500m"
restartPolicy: OnFailure 示例中组调度(Gang)需要满足以下三个维度:
- partitionSize:Parameter Server(PS)任务中每个分组至少需要1个Pod可调度后该分组可调度,Worker任务中每个分组至少需要2个Pod可调度后该分组可调度。
- minPartitions:每个任务内最小的分组数量,PS任务中至少需要一个分组可调度,Worker任务中至少需要2个分组可调度。
- minAvailable:Job内最小的Pod数量。Job需要至少5个Pod可调度。
当集群资源不足仅满足5个Pod可以被调度时,优先按照多维Gang调度的约束进行Pod调度,确保调度的Pod满足各个Partition的Pod数量要求和Partition的数量要求。PS任务启动了一个完整分组,而Worker任务启动了2个完整分组,从而满足了整体任务的最小启动要求。
执行kubectl get pods命令查看负载信息,返回类似信息如下。
NAME READY STATUS RESTARTS AGE sample-ps-0 1/1 Running 0 34s sample-ps-1 0/1 Pending 0 34s sample-worker-0 1/1 Running 0 34s sample-worker-1 1/1 Running 0 34s sample-worker-2 1/1 Running 0 34s sample-worker-3 1/1 Running 0 34s sample-worker-4 0/1 Pending 0 61s sample-worker-5 0/1 Pending 0 61s sample-worker-6 0/1 Pending 0 61s sample-worker-7 0/1 Pending 0 61s
创建Kthena ModelServing推理负载
当分布式推理负载存在Prefill和Decode两种角色时,每个角色内可以有多个Pod。单个Prefill或Decode角色内的多个Pod需要默认满足Gang调度能力,即一个角色实例中的Pod要么全部被调度,要么一个都不调度。Prefill和Decode角色可以有多个实例,存在不同的组合方式。例如,在4P2D的场景下,只有满足最低2P1D数量要求时,才能为负载Pod分配资源。
Kthena提供的模型服务编排(ModelServing)已支持通过Volcano调度推理负载。在ModelServing中,可以直接定义推理负载在不同维度的Gang调度要求,并通过Volcano实现负载的多维度Gang调度。创建ModelServing时,只需指定gangPolicy和Role,ModelServing控制器将根据gangPolicy和Role定义自动创建并管理PodGroup的分组,示例如下。
apiVersion: workload.serving.volcano.sh/v1alpha1
kind: ModelServing
metadata:
name: sample
namespace: default
spec:
schedulerName: volcano
replicas: 1
template:
restartGracePeriodSeconds: 60
gangPolicy:
minRoleReplicas: # 可选,各Role最少Repilca数量的Gang调度条件
prefill: 2
decode: 2
roles:
- name: prefill
replicas: 4 # 必选,Role Replica数量
entryTemplate:
spec:
containers:
- name: leader
image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
resources:
limits:
cpu: "0.5"
requests:
cpu: "0.5"
workerReplicas: 1 # 可选,Role Prefill内Worker Pod数量
workerTemplate:
spec:
containers:
- name: worker
image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
resources:
limits:
cpu: "0.5"
requests:
cpu: "0.5"
- name: decode
replicas: 4
entryTemplate:
spec:
containers:
- name: leader
image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
resources:
limits:
cpu: "0.5"
requests:
cpu: "0.5"
workerReplicas: 1 # 可选,Role Replica内Worker Pod数量
workerTemplate:
spec:
containers:
- name: worker
image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
resources:
limits:
cpu: "0.5"
requests:
cpu: "0.5" 示例中组调度(Gang)需要满足是两个维度:
- workerReplicas:每个Role Replica内最少Worker Pod数量。Role Replica内至少需要entryReplica (1) + workerReplicas个Pod可调度后该Role Replica可调度。
- minRoleReplicas:各个Role最小的副本数量,示例中Prefill和Decode各自至少需要2个副本(2P2D)才能调度。
ModelServing工作负载的最少Pod数由最少Role replicas数量*Role Pod数量计算得到,您无需单独设置。
在资源不足时可以看到Prefill和Decode Role各自启动了2个Replica,每个Replica内2个Pod。
NAME READY STATUS RESTARTS AGE sample-0-decode-0-0 1/1 Running 0 8s sample-0-decode-0-1 1/1 Running 0 8s sample-0-decode-1-0 1/1 Running 0 8s sample-0-decode-1-1 1/1 Running 0 7s sample-0-decode-2-0 0/1 Pending 0 7s sample-0-decode-2-1 0/1 Pending 0 7s sample-0-decode-3-0 0/1 Pending 0 7s sample-0-decode-3-1 0/1 Pending 0 7s sample-0-prefill-0-0 1/1 Running 0 8s sample-0-prefill-0-1 1/1 Running 0 8s sample-0-prefill-1-0 1/1 Running 0 8s sample-0-prefill-1-1 1/1 Running 0 8s sample-0-prefill-2-0 0/1 Pending 0 8s sample-0-prefill-2-1 0/1 Pending 0 8s sample-0-prefill-3-0 0/1 Pending 0 8s sample-0-prefill-3-1 0/1 Pending 0 8s