CPU拓扑感知调度

在同一节点上同时运行多个Pod时,Pod之间可能会因为CPU资源的争抢带来频繁的上下文切换,导致性能抖动。针对性能敏感型应用,您可以启用CPU拓扑感知调度功能,将Pod固定在节点的CPU Core上运行,缓解因CPU上下文切换、跨NUMA访存导致的应用性能下降问题。

说明

为了帮助您更好地理解本文档并使用本功能,推荐您参见Kubernetes官方文档了解Pod Qos类为容器和 Pod 分配内存资源节点上的CPU管理策略(例如CPU管理策略none策略、static策略)等概念。

使用场景

在Kubernetes集群中,多个Pod会在同一个节点上共享CPU核心。但在以下场景中,某些应用可能需要固定在部分CPU核心上运行。

  • 应用尚未完成对云原生场景的适配,例如在设置线程数量时未考虑容器规格(而是整机物理核数量),导致应用出现性能下降问题。

  • 应用运行在神龙裸金属(Intel、AMD)等多核机器上,且出现大量因跨NUMA访存带来的应用性能下降问题。

  • 应用对CPU上下文切换十分敏感,无法承受因此带来的性能抖动。

虽然Kubernetes提供了CPU Manager以解决此问题,支持为对CPU亲和性和性能有更高要求的应用配置static策略,允许这些应用独占节点上的特定CPU Core,以获得稳定的计算资源。但CPU Manager仅提供节点维度的CPU调度选择,无法在集群维度选择最优的CPU Core组合。此外,通过CPU Manager为应用配置static策略时,Pod仅支持对Guaranteed类型的Pod生效,即Pod中的每个容器必须声明了CPU Request和CPU Limit且两者取值相等,无法适用于其他类型的Pod,包括Burstable和BestEffort。

为此,ACK集群基于新版的Scheduling Framework实现了CPU拓扑感知调度功能,支持通过Pod Annotation直接启用,以更好地保障CPU敏感型工作负载的服务性能。

前提条件

  • 已创建ACK集群Pro版,且节点池的CPU Policy为None,请参见创建ACK Pro版集群

  • 已安装ack-koordinator组件,且组件版本为0.2.0及以上,请参见ack-koordinator

费用说明

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

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

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

步骤一:部署示例应用

本文以一个Nginx应用为例,介绍如何启用CPU拓扑感知调度,实现CPU绑核。

  1. 使用以下YAML示例,部署一个Nginx应用。

    展开查看YAML文件内容

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          nodeSelector:
            policy: intel
          containers:
          - name: nginx
            image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0
            ports:
            - containerPort: 80
            resources:
              requests:
                cpu: 4
                memory: 8Gi
              limits:
                cpu: 4
                memory: 8Gi
            volumeMounts:
               - mountPath: /etc/nginx/nginx.conf
                 name: nginx
                 subPath: nginx.conf
          volumes:
            - name: nginx
              configMap:
                name: nginx-configmap
                items:
                  - key: nginx_conf
                    path: nginx.conf
  2. 在Pod对应的节点上,执行以下命令,查看当前容器的CPU核心绑定情况。

    # 具体路径可根据Pod的UID以及Container的ID拼接得到。
    cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf9b79bee_eb2a_4b67_befe_51c270f8****.slice/cri-containerd-aba883f8b3ae696e99c3a920a578e3649fa957c51522f3fb00ca943dc2c7****.scope/cpuset.cpus

    预期输出:

    # 未指定自动绑核策略前,可使用的CPU编号范围为0~31,表示CPU目前没有约束。
    0-31

步骤二:启用CPU拓扑感知调度功能

您可以通过Pod Annotation启用CPU拓扑感知调度功能,实现对Pod的绑核,具体策略如下。

重要

在使用CPU拓扑感知调度时,请勿在Pod上直接指定nodeNamekube-scheduler并不参与这类Pod的调度过程。您可以使用nodeSelector等字段配置亲和性策略,来指定节点调度。

普通绑核策略

您可以通过Pod Annotation cpuset-scheduler启用CPU拓扑感知调度功能,系统会为您实现CPU绑核。

  1. 在Pod YAML的metadata.annotations中,配置cpuset-schedulertrue,启用CPU拓扑感知调度。

    说明

    如需在工作负载(例如Deployment)中配置,请在template.metadata字段下配置Pod对应的Annotation。

  2. Containers字段下,配置resources.limit.cpu的取值(该值需为整数),限定CPU绑核范围。


展开查看启用了普通绑核策略的示例YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      annotations:
        cpuset-scheduler: "true" # 设置为true,启用CPU拓扑感知调度。
      labels:
        app: nginx
    spec:
      nodeSelector:
        policy: intel
      containers:
      - name: nginx
        image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 4
            memory: 8Gi
          limits:
            cpu: 4 # 设置resources.limit.cpu值,需为整数。
            memory: 8Gi
        volumeMounts:
           - mountPath: /etc/nginx/nginx.conf
             name: nginx
             subPath: nginx.conf
      volumes:
        - name: nginx
          configMap:
            name: nginx-configmap
            items:
              - key: nginx_conf
                path: nginx.conf

自动绑核策略

您可以通过Annotation开启CPU拓扑感知调度功能并同步启用自动绑核策略。配置后,调度器会根据Pod规格自动规划绑核数量,尽量避免出现跨NUMA访问内存的情况。

  1. 在Pod YAML的metadata.annotations中,配置cpuset-schedulertrue,且cpu-policystatic-burst,启用自动绑核策略。

    说明

    如需在工作负载(例如Deployment)中配置,请在template.metadata字段下配置Pod对应的Annotation。

  2. Containers字段下,配置resources.limit.cpu的取值(该值需为整数),做为CPU绑核范围的参考值。


展开查看启用了自动绑核策略的示例YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      annotations:
        cpuset-scheduler: "true" # 设置为true,启用CPU拓扑感知调度。
        cpu-policy: "static-burst" # 设置为static-burst,启用自动绑核策略。
      labels:
        app: nginx
    spec:
      nodeSelector:
        policy: intel
      containers:
      - name: nginx
        image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 4
            memory: 8Gi
          limits:
            cpu: 4 # 做为CPU绑核范围的参考值,需为整数。
            memory: 8Gi
        volumeMounts:
           - mountPath: /etc/nginx/nginx.conf
             name: nginx
             subPath: nginx.conf
      volumes:
        - name: nginx
          configMap:
            name: nginx-configmap
            items:
              - key: nginx_conf
                path: nginx.conf

结果验证

以普通绑核策略为例,验证CPU拓扑感知调度是否成功启用。自动绑核策略的验证流程类似。

在Pod对应的节点上,再次执行以下命令,查看启用自动绑核策略后容器的CPU核心绑定情况。

# 具体路径可根据Pod的UID以及Container的ID拼接得到。
cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf9b79bee_eb2a_4b67_befe_51c270f8****.slice/cri-containerd-aba883f8b3ae696e99c3a920a578e3649fa957c51522f3fb00ca943dc2c7****.scope/cpuset.cpus

预期输出:

# 和limit数量相同
0-3

预期输出表明,容器可用的CPU编号范围为0~3,与YAML中声明的resources.limit.cpu一致。

相关文档

  • Kubernetes对节点的GPU拓扑信息不感知,调度过程中对GPU的选择比较随机,选择不同的GPU组合训练速度会存在较大的差异。推荐您启用GPU拓扑感知调度,在节点的GPU组合中选择具有最优训练速度的组合,请参见GPU拓扑感知调度

  • 您可以将集群中已分配但未使用的资源量化并提供给低优先级任务使用,以实现对集群资源的超卖,请参见动态资源超卖