使用负载感知调度

ACK默认调度器仅会使用所需资源(Request)筛选规则进行节点筛选。推荐您在ACK集群Pro版中启用调度器的负载感知调度功能。该功能会根据节点的实际负载情况,将Pod优先调度到负载较低的节点,以实现节点负载均衡,降低节点故障风险。

前提条件

  • 已安装ack-koordinator组件,且版本为1.1.1-ack.1及以上。具体操作,请参见ack-koordinator(ack-slo-manager)

  • 对于不同版本的ACK集群,已确保支持负载感知调度的ACK调度器kube-scheduler满足如下版本要求。

    ACK版本

    支持负载感知调度的ACK调度器版本

    1.26及以上

    所有版本均可支持

    1.24

    v1.24.6-ack-4.0及以上

    1.22

    v1.22.15-ack-4.0及以上

费用说明

ack-koordinator组件本身的安装和使用是免费的,不过需要注意的是,在以下场景中可能产生额外的费用:

  • ack-koordinator是非托管组件,安装后将占用Worker节点资源。您可以在安装组件时配置各模块的资源申请量。

  • ack-koordinator默认会将资源画像、精细化调度等功能的监控指标以Prometheus的格式对外透出。若您配置组件时开启了ACK-Koordinator开启Prometheus监控指标选项并使用了阿里云Prometheus服务,这些指标将被视为自定义指标并产生相应费用。具体费用取决于您的集群规模和应用数量等因素。建议您在启用此功能前,仔细阅读阿里云Prometheus计费说明,了解自定义指标的免费额度和收费策略。您可以通过账单和用量查询,监控和管理您的资源使用情况。

使用限制

仅支持ACK集群Pro版。具体操作,请参见创建ACK Pro版集群

负载感知调度介绍

负载感知调度是ACK调度器kube-scheduler基于Kubernetes Scheduling Framework实现的插件。与Kubernetes原生调度策略不同的是,原生调度器主要基于资源的分配情况进行调度,而ACK调度器可以感知节点实际的资源负载情况。通过参考节点负载的历史统计并对新调度Pod进行预估,调度器会将Pod优先调度到负载较低的节点,实现节点负载均衡的目标,避免出现因单个节点负载过高而导致的应用程序或节点故障。

如下图所示,已分配资源量(Requested)代表已申请的资源量,已使用资源量(Usage)代表真实使用的资源量,只有真实使用的资源才会被算作真实负载。面对相同的节点情况,ACK调度器将新创建的Pod分配到负载更低的节点B。

1

考虑到节点的利用率会随着时间、集群环境、工作负载的流量或请求等动态变化,ack-koordinator组件还提供重调度能力,防止在Pod调度完成后,集群再次出现负载极端不均衡的情况。通过将负载感知调度和热点打散重调度结合使用,可以获得集群最佳的负载均衡效果。关于热点打散重调度,请参见使用负载热点打散重调度

工作原理

负载感知调度功能由kube-schedulerack-koordinator组件配合完成。其中,ack-koordinator组件负责节点资源利用率的采集和上报,ACK调度器会根据利用率数据对节点进行打分排序,优先选取负载更低的节点参与调度。关于组件架构的详细介绍,请参见ack-koordinator组件架构

策略说明

策略名称

说明

节点筛选

开启节点筛选后,调度器会根据节点实际负载水位进行筛选。当某节点实际负载超过配置的负载阈值时,调度器会拒绝将Pod调度到该节点上。筛选功能默认不开启,需要您在组件配置按需修改loadAwareThreshold参数,详细信息,请参见Kube Scheduler参数配置

重要

若集群已经开启了节点自动弹性伸缩,配置负载感知阈值筛选可能会引起非预期的节点扩缩,原因是自动弹性伸缩的扩容是依据Pod是否Pending,而缩容是依据集群的分配率水位。若您需要同时开启自动弹性伸缩和负载感知的节点筛选,请结合集群容量和利用率适当调整配置,详见启用节点自动伸缩

节点排序

负载感知调度考虑CPU和内存两个资源维度。调度器在为节点打分时采用了加权的计算方式,优先选取分数更高的节点参与调度。在组件配置勾选Pod 调度时启用负载感知的打分能力,开启后,还可进一步对CPU和内存权重支持自定义配置,详细信息,请参见Kube Scheduler参数配置中的loadAwareResourceWeight

计算公式:((1 - CPU资源利用率) * CPU权重配置 + (1 - 内存资源利用率) * 内存权重配置)/(CPU权重 + 内存权重),其中CPU和内存的资源利用率单位为百分比。

资源利用率统计算法

资源利用率的统计算法支持多种类型的配置,包括平均值和分位值。默认为近5分钟的平均值,详细信息,请参见Kube Scheduler参数配置。此外,内存资源维度的用量数据排除了Page Cache,因为Page Cache可以被操作系统回收。需要注意的是通过kubectl top node命令查询时,返回的利用率会包含Page Cache,您可以通过使用阿里云Prometheus监控查看真实的内存用量信息。

步骤一:开启负载感知调度

重要

请务必完成ack-koordinator组件的安装,且版本为1.1.1-ack.1及以上,否则负载感知调度功能无法生效。

  1. 登录容器服务管理控制台,在左侧导航栏选择集群

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择运维管理 > 组件管理

  3. 组件管理页面,定位Kube Scheduler,然后在Kube Scheduler卡片中单击配置

  4. 在对话框中参考下表按需进行相关配置,然后单击确定

    下表介绍负载感知调度的主要配置项,关于详细配置以及各配置依赖的组件版本请参见kube-scheduler自定义调度器参数

    配置项

    类型

    说明

    取值

    示例值

    loadAwareThreshold

    由资源名resourceName和权重threshold组成的列表。

    对应节点筛选策略,表示资源类型对应的阈值。

    • resourceName:支持cpumemory两种类型。

    • threshold:[0,100]。

    默认值为空,即不开启筛选功能。

    • resourceName:cpu

    • threshold:80

    loadAwareResourceWeight

    由资源名resourceName和权重resourceWeight组成的列表。

    对应节点排序策略,表示资源类型对应的打分权重。需要勾选Pod 调度时启用负载感知的打分能力

    • resourceName:使用schema进行校验,仅支持cpumemory

    • resourceWeight:整数,取值范围为[1,100]。

    默认值为cpu=1、memory=1。

    • resourceName:cpu

    • resourceWeight:1

    loadAwareAggregatedUsageAggragationType

    enum

    负载统计值的聚合类型。各类型具体含义为:

    • avg:平均值。

    • p50:50%分位值,即中位数。

    • p90p95p99:分别表示90%、95%、99%分位值。

    • avg

    • p50

    • p90

    • p95

    • p99

    默认值为avg

    p90

    在左侧导航栏,单击集群信息,然后在右侧页面单击基本信息页签,等待集群状态变为运行中,表示负载感知调度功能开启成功。

步骤二:验证负载感知调度

下文以拥有3台4 Core 16 GiB节点的集群为例进行说明。

  1. 使用如下YAML内容,创建stress-demo.yaml文件。

    展开查看详细YAML文件。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: stress-demo
      namespace: default
      labels:
        app: stress-demo
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: stress-demo
      template:
        metadata:
          name: stress-demo
          labels:
            app: stress-demo
        spec:
          containers:
            - args:
                - '--vm'
                - '2'
                - '--vm-bytes'
                - '1600M'
                - '-c'
                - '2'
                - '--vm-hang'
                - '2'
              command:
                - stress
              image: polinux/stress
              imagePullPolicy: Always
              name: stress
              resources:
                limits:
                  cpu: '2'
                  memory: 4Gi
                requests:
                  cpu: '2'
                  memory: 4Gi
          restartPolicy: Always
  2. 执行如下命令,创建Pod。创建完成后,按需提升其中一个节点的负载水位。

    kubectl create -f stress-demo.yaml
    # 预期输出
    deployment.apps/stress-demo created
  3. 执行如下命令,观察Pod的状态,直至开始运行。

    kubectl get pod -o wide

    预期输出:

    NAME                           READY   STATUS    RESTARTS   AGE   IP           NODE                    NOMINATED NODE   READINESS GATES
    stress-demo-7fdd89cc6b-g****   1/1     Running   0          82s   10.XX.XX.112   cn-beijing.10.XX.XX.112   <none>           <none>

    预期输出表明,Pod stress-demo-7fdd89cc6b-g****调度在节点cn-beijing.10.XX.XX.112上。

    等待3分钟左右,确保Pod完成初始化,节点负载水位已完成提升。

  4. 执行如下命令,检查每个节点的负载。

    kubectl top node

    预期输出:

    NAME                    CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
    cn-beijing.10.XX.XX.110   92m          2%     1158Mi          9%
    cn-beijing.10.XX.XX.111   77m          1%     1162Mi          9%
    cn-beijing.10.XX.XX.112   2105m        53%    3594Mi          28%

    预期输出表明,节点cn-beijing.10.XX.XX.111负载最低,节点cn-beijing.10.XX.XX.112的负载最高,此时集群已经出现节点负载不均的情况。

  5. 使用以下YAML内容,创建nginx-with-loadaware.yaml文件。

    展开查看详细YAML文件。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-with-loadaware
      namespace: default
      labels:
        app: nginx
    spec:
      replicas: 6
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          name: nginx
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx
            resources:
              limits:
                cpu: 500m
              requests:
                cpu: 500m
  6. 执行如下命令,创建Pod。

    kubectl create -f nginx-with-loadaware.yaml
    # 预期输出
    deployment/nginx-with-loadawre created
  7. 执行如下命令,查看Pod调度详情。

    kubectl get pods | grep nginx

    预期输出:

    nginx-with-loadaware-5646666d56-2****   1/1     Running   0          18s   10.XX.XX.118   cn-beijing.10.XX.XX.110   <none>           <none>
    nginx-with-loadaware-5646666d56-7****   1/1     Running   0          18s   10.XX.XX.115   cn-beijing.10.XX.XX.110   <none>           <none>
    nginx-with-loadaware-5646666d56-k****   1/1     Running   0          18s   10.XX.XX.119   cn-beijing.10.XX.XX.110   <none>           <none>
    nginx-with-loadaware-5646666d56-q****   1/1     Running   0          18s   10.XX.XX.113   cn-beijing.10.XX.XX.111   <none>           <none>
    nginx-with-loadaware-5646666d56-s****   1/1     Running   0          18s   10.XX.XX.120   cn-beijing.10.XX.XX.111   <none>           <none>
    nginx-with-loadaware-5646666d56-z****   1/1     Running   0          18s   10.XX.XX.116   cn-beijing.10.XX.XX.111   <none>           <none>

    预期输出表明,集群开启负载感知调度功能后,能感知节点负载,通过运用调度策略将Pod优先调度到除cn-beijing.10.XX.XX.112以外的节点上。

相关操作

修改负载感知调度配置

  1. 登录容器服务管理控制台,在左侧导航栏选择集群

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择运维管理 > 组件管理

  3. 组件管理页面,查找Kube Scheduler,然后在Kube Scheduler卡片中单击配置

  4. Kube Scheduler 参数配置对话框,修改负载感知调度的相关配置参数,单击确定

    在左侧导航栏,单击集群信息,然后在右侧页面单击基本信息页签,等待集群状态变为运行中,表示更新完成。

关闭负载感知调度

Kube Scheduler 参数配置对话框,取消选中Pod 调度时启用负载感知的打分能力,并删除loadAwareResourceWeightloadAwareThreshold参数,单击确定

在左侧导航栏,单击集群信息,然后在右侧页面单击基本信息页签,等待集群状态变为运行中,表示更新完成。

常见问题

对于一批新创建的Pod,为什么没有全部调度到负载最低的节点?

如果调度器将一批新创建的Pod全部调度到当前负载最低的节点,那么这个节点反而可能很快就会成为负载热点,这是因为新Pod在启动后会增加节点的负载。

因此,负载感知调度插件在计算节点打分时,若节点中有利用率还未上报的新Pod,会对打分结果进行适当调整,避免过量调度而产生新的热点。

除了节点负载水位,还有哪些因素会影响调度结果?

K8s调度器由多个插件组成,在调度过程中很多插件都会参与到节点排序的打分计算,例如亲和性插件、拓扑分布插件,节点的最终排序会受这些插件共同影响,您可以根据实际情况,按需调整各插件的打分权重。

调度器升级为新版本后,是否继续支持已通过旧版本协议使用的负载感知调度功能?

如需使用旧版本的负载感知调度功能,需为Pod添加Annotation alibabacloud.com/loadAwareScheduleEnabled: "true"

ACK调度器兼容旧版本协议,您可无缝升级至新版本。升级后,建议您通过步骤一:开启负载感知调度为调度器开启全局的负载均衡调度策略,以减少对Pod配置的改动。

重要

ACK调度器在1.22版本将持续保持对旧版本协议的兼容,在1.24版本的兼容期限截止至2023年08月30日。建议您升级集群版本,并使用新版本的负载感知调度功能配置方式。关于集群升级,请参见手动升级集群

各版本协议的支持情况和组件版本具体要求如下。

1.26及以上

ACK调度器版本

ack-koordinator(ack-slo-manager)版本要求

Pod Annotation协议

控制台参数配置开关

所有ACK调度器版本

≥1.1.1-ack.1

不支持

支持

1.24

ACK调度器版本

ack-koordinator(ack-slo-manager)版本要求

Pod Annotation协议

控制台参数配置开关

≥v1.24.6-ack-4.0

≥1.1.1-ack.1

支持

支持

≥v1.24.6-ack-3.1且<v1.24.6-ack-4.0

≥0.8.0

支持

不支持

1.22及以下

ACK调度器版本

ack-koordinator(ack-slo-manager)版本要求

Pod Annotation协议

控制台参数配置开关

≥1.22.15-ack-4.0

≥1.1.1-ack.1

支持

支持

≥1.22.15-ack-2.0且<1.22.15-ack-4.0

≥0.8.0

支持

不支持

  • ≥v1.20.4-ack-4.0且≤v1.20.4-ack-8.0

  • v1.18-ack-4.0

≥0.3.0且<0.8.0

支持

不支持