全部產品
Search
文件中心

Container Service for Kubernetes:CPU拓撲感知調度

更新時間:Dec 27, 2025

當多個應用運行在同一節點時,CPU資源爭搶和頻繁的環境切換可能導致效能敏感型應用產生抖動。通過啟用CPU拓撲感知調度,可將應用進程獨佔綁定到指定CPU核心(即CPU綁核),減少因核心切換和跨NUMA訪存帶來的效能不確定性。

工作原理

Kubernetes預設依賴核心的CFS調度器(Completely Fair Scheduler)來實現CPU的負載平衡。該調度器通過公平分配CPU時間片將負載“打散”到各個核心,但可能因忽略了CPU的物理拓撲導致效能敏感型應用的效能抖動。

Kubernetes的CPU Manager(static策略)能夠為Pod綁定並獨佔CPU核心,但仍存在以下局限:

  • 調度器無感知:原生kube-scheduler僅在節點維度做決策,無法感知整個叢集的CPU拓撲,不能為Pod在全域範圍內尋找最優的物理核心布局。

  • 拓撲不敏感:static策略在節點內分配核心時,不感知NUMA架構,可能導致跨NUMA節點的記憶體訪問,引入額外延遲。

  • 靈活性不足:該策略嚴格要求Pod的QoS為Guaranteed,不適用於BurstableBestEffort類型的Pod。

為此,ACK基於新版Scheduling Framework提供了增強CPU拓撲感知調度能力,由ACK kube-scheduler和ack-koordinator協同完成。

  1. 節點拓撲上報:ack-koordinator即時感知本地的CPU物理拓撲(如Socket、NUMA、緩衝),並將其上報至調度中心。

  2. 全域拓撲感知調度:kube-scheduler基於全域拓撲資訊,在叢集範圍內為Pod篩選出當前最優節點,並規劃核心分配方案(如在選擇最優節點時預設尋找已綁定應用數量最少的核)。該分配方案會作為調度結果寫入Pod的Annotation中。

  3. 本地綁核執行:Pod調度至目標節點後,ack-koordinator會根據Pod的 Annotation 並修改其對應Cgroup的cpuset.cpus檔案,以完成物理核心的綁定。

適用情境

  • 效能敏感型應用:對CPU環境切換延遲極度敏感,如高頻交易、即時資料處理。

  • NUMA敏感型應用:部署在神龍裸金屬(Intel、AMD)等多核、多Socket伺服器上,且業務效能受記憶體訪問延遲影響巨大,期望避免跨NUMA訪存。

  • 確定性算力需求:需要穩定、可預期的計算能力,如科學計算、巨量資料分析任務。

  • 遺留應用適配:應用尚未完成對雲原生情境的適配,例如在設定線程數量時未考慮容器規格(而是整機物理核心數量),導致效能下降。

重要

不建議在以下情境中啟用此功能:

  • CPU超賣環境:綁核的資源獨佔特性與超賣的資源共用模型存在不相容,可能造成資源浪費並幹擾超賣調度邏輯。

  • 通用型或I/O密集型應用:大多數Web服務、中介軟體等應用對CPU核心切換不敏感,無需啟用此功能。

準備工作

  • 已建立ACK託管叢集Pro版,且已配置節點池的CPU Policy(cpuManagerPolicy)為none。請參見自訂節點池kubelet配置配置cpuManagerPolicy取值。

  • 已安裝ack-koordinator,且組件版本為0.2.0及以上。

步驟一:部署樣本應用

本文以一個Nginx應用為例,介紹如何啟用CPU拓撲感知調度,實現CPU綁核。

  1. 建立nginx-app.yaml

    展開查看YAML

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      namespace: default
      labels:
        app: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          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
            command:
            - "sleep"
            - "infinity"
            resources:
              requests:
                cpu: 4
                memory: 8Gi
              limits:
                # 設定cpu值,需為整數。
                cpu: 4 
                memory: 8Gi
  2. 部署應用。

    kubectl apply -f nginx-app.yaml
  3. 登入Pod所在節點,擷取Pod的UID和Container ID。

    • 擷取Pod名稱。
      執行 kubectl get pods -n <your-namespace> 查看Pod名稱,如 nginx-deployment-6f5899*****

    • 擷取Pod UID。

      # 將 <your-pod-name> 替換為Pod實際名稱
      kubectl get pod <your-pod-name> -n default -o jsonpath='{.metadata.uid}{"\n"}'

      預期輸出:

        uid: a78a02b5-c87f-4e74-9ddd-254c163*****
    • 擷取Container ID。

      # 將 <your-pod-name> 替換為Pod實際名稱
      kubectl describe pod <your-pod-name> -n default

      在輸出的Containers欄位下定位Container ID,並刪去首碼(如containerd://)。

      預期輸出:

      Containers:
        nginx:
          Container ID:   containerd://b8b88a70096aabb0aea197dd2aba78d15bcbe9145198ef46a0474b31*****
  4. 確認節點的cgroup版本。

    stat -fc %T /sys/fs/cgroup/
    • 輸出為 cgroup_root:系統使用 cgroup v1。

    • 輸出為 cgroup2fs:系統使用 cgroup v2。

  5. 根據cgroup版本執行對應的驗證命令,查看CPU綁核情況。

    在cgroup路徑中,Pod UID中的-需替換為_。如原始Pod UID為a78a02b5-c87f-4e74-9ddd-254c163*****,則路徑中使用的格式為a78a02b5_c87f_4e74_9ddd_254c163*****
    • cgroup v1:

      # 將 <POD_UID> 和 <CONTAINER_ID> 替換為實際值
      cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus
    • cgroup v2:

      # 將 <POD_UID> 和 <CONTAINER_ID> 替換為實際值
      cat /sys/fs/cgroup/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus.effective

    預期輸出為一個範圍,代表容器可以使用節點上的所有核心,未進行綁定。

    0-31

步驟二:啟用CPU拓撲感知調度功能

可通過為Pod添加Annotation來啟用CPU拓撲感知調度。

  • 普通綁核策略:通用策略,遵循1:1的綁核原則,為Pod綁定resources.limits.cpu所指定的數量的核心。優先選擇同一NUMA節點內的CPU核,以保證良好的記憶體訪問效能。

  • 自動綁核策略:針對特定硬體最佳化的策略,優先通過綁定一個完整的物理核心簇(如AMD CPU的CCX/CCD)來最大化CPU局部性並提升並發度。推薦在特定的大規格(如32核及以上)AMD機型上使用。

重要

啟用CPU拓撲感知調度時,請勿在Pod上直接指定nodeNamekube-scheduler不參與此類Pod的調度過程。可使用nodeSelector等欄位配置親和性策略來指定節點調度。

普通綁核策略

  • 配置方法:

    • 在YAML中添加Annotation cpuset-scheduler: "true"

      • Pod中:在metadata.annotations欄位中添加

      • 工作負載(例如Deployment)中:在spec.template.metadata.annotations欄位中添加

    • Containers欄位中配置resources.limits.cpu的取值(需為整數),限定CPU綁核範圍。

  • 配置樣本:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      namespace: default
      labels:
        app: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          annotations:
            # 設定為true,啟用CPU拓撲感知調度
            cpuset-scheduler: "true" 
          labels:
            app: nginx
        spec:
          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
            command:
            - "sleep"
            - "infinity"
            resources:
              requests:
                cpu: 4
                memory: 8Gi
              limits:
                # 設定cpu值,需為整數
                cpu: 4 
                memory: 8Gi
  • 結果驗證:

    可通過以下兩種方式查看。

    查看節點Cgroup檔案

    等待Pod正常運行後,再次登入其所在節點,查看CPU綁核情況。

    Pod UID中的-需替換為_
    • cgroup v1:

      # 將 <POD_UID> 和 <CONTAINER_ID> 替換為實際值
      cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus
    • cgroup v2:

      # 將 <POD_UID> 和 <CONTAINER_ID> 替換為實際值
      cat /sys/fs/cgroup/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus.effective

    預期輸出為一組核心ID,與limits.cpu: 4的設定相符,表明綁核成功。

    0-3

    檢查Pod Annotation

    Pod調度至目標節點後,ack-koordinator會根據Pod的 Annotation 並修改其對應Cgroup的cpuset.cpus檔案,以完成物理核心的綁定。

    查看Pod cpuset資訊。

    # 將 <your-pod-name> 替換實際Pod名稱
    kubectl get pod <your-pod-name> -n default -o yaml | grep "cpuset:"

    預期輸出:

            cpuset: '{"nginx":{"0":{"elems":{"0":{},"1":{},"2":{},"3":{}}}}}'

    輸出結果說明:

    • "nginx":{...}:針對名為nginx的容器的配置。

    • "0":{...}:最外層的鍵"0"代表NUMA節點ID。本樣本表示所有綁定的核都位於同一NUMA Node 0上,避免了跨NUMA訪存的效能損耗。

    • "elems":{"0":{},"1":{},"2":{},"3":{}}:鍵代表被綁定的物理CPU核心ID。此樣本中,容器被成功綁定到了0、1、2、3這四個核心上,與limits.cpu: 4相符。

自動綁核策略

  • 配置方法:

    • 添加兩個Annotation:cpuset-scheduler: "true"cpu-policy: "static-burst"

      • Pod中:在metadata.annotations欄位中添加

      • 工作負載(例如Deployment)中:在spec.template.metadata.annotations欄位中添加

    • Containers欄位中配置resources.limits.cpu的取值(需為整數),限定CPU綁核範圍。

  • 配置樣本:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      namespace: default
      labels:
        app: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          annotations:
            # 設定為true,啟用CPU拓撲感知調度
            cpuset-scheduler: "true" 
            # 設定為static-burst,啟用自動綁核與NUMA親和策略
            cpu-policy: "static-burst" 
          labels:
            app: nginx
        spec:
          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
            command:
            - "sleep"
            - "infinity"
            resources:
              requests:
                cpu: 4
                memory: 8Gi
              limits:
                # 設定cpu值,需為整數
                cpu: 4
                memory: 8Gi
  • 結果驗證:

    自動綁核策略會即時分析節點的CPU拓撲和資源使用方式,綁核心數量可能會大於Pod的顯式請求。綁核情況可通過以下兩種方式查看。

    查看節點Cgroup檔案

    等待Pod正常運行後,再次登入其所在節點,查看CPU綁核情況。

    Pod UID中的-需替換為_
    • cgroup v1:

      # 將 <POD_UID> 和 <CONTAINER_ID> 替換為實際值
      cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus
    • cgroup v2:

      # 將 <POD_UID> 和 <CONTAINER_ID> 替換為實際值
      cat /sys/fs/cgroup/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus.effective

    預期輸出為一組確切的核心ID,表明綁核成功。

    0-7

    檢查Pod Annotation

    Pod調度至目標節點後,ack-koordinator會根據Pod的 Annotation 並修改其對應Cgroup的cpuset.cpus檔案,以完成物理核心的綁定。

    查看Pod cpuset資訊。

    # 將 <your-pod-name> 替換實際Pod名稱
    kubectl get pod <your-pod-name> -n default -o yaml | grep "cpuset:"

    預期輸出:

        cpuset: '{"nginx":{"0":{"elems":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{}}}}}'

    輸出結果說明:

    • "nginx":{...}:針對名為nginx的容器的配置。

    • "0":{...}:最外層的鍵"0"代表NUMA節點ID。本樣本表示所有綁定的核都位於同一NUMA Node 0上,避免了跨NUMA訪存的效能損耗。

    • "elems":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{}}:鍵代表被綁定的物理CPU核心ID。此樣本中,容器已綁定至0~7核心上。

相關操作

停用CPU拓撲感知調度(CPU核心解除綁定)

  1. 編輯應用YAML,從spec.template.metadata.annotations中移除Annotation cpuset-scheduler: "true"cpu-policy: "static-burst"(如有)。

  2. 在業務低峰期應用修改後的YAML,等待Pod重啟後變更生效。

重要

解除綁定後,Pod 進程不再被綁定到特定物理核心,可能會在節點所有可用 CPU 核心之間切換。潛在影響包括:

  • 因跨核心的環境切換,CPU 使用率可能微幅上升。

  • 對於計算密集型應用,由於無法獨佔核心,可能會重新出現因 CPU 資源爭搶導致的效能抖動。

  • 當多個高負載 Pod 的進程被調度至同一核心時,可能導致該核心負載瞬時過高,進而觸發容器的 CPU 限流(Throttling)。

生產環境使用建議

  • 可觀測性:在啟用綁核前後,接入阿里雲Prometheus監控,密切關注應用的關鍵效能指標(如RT、QPS)以及節點的CPU使用率、CPU Throttling等指標,關注綁核帶來的效能變化。

  • 分批變更:對於多副本應用,建議採用金絲雀發布或分批更新的方式,逐步啟用或停用綁核策略,以控制變更風險。

費用說明

ack-koordinator組件本身的安裝和使用免費,但在以下情境中可能產生額外費用。

  • ack-koordinator是非託管組件,安裝後將佔用Worker節點資源。您可以在安裝組件時配置各模組的資源申請量。

  • ack-koordinator預設會將資源畫像、精細化調度等功能的監控指標以Prometheus的格式對外透出。若您配置組件時開啟了ACK-Koordinator開啟Prometheus監控指標選項並使用了阿里雲Prometheus服務,這些指標將被視為自訂指標併產生相應費用。具體費用取決於您的叢集規模和應用數量等因素。建議您在啟用此功能前,仔細閱讀阿里雲PrometheusPrometheus 執行個體計費,瞭解自訂指標的免費額度和收費策略。您可以通過用量查詢,監控和管理您的資源使用方式。

相關文檔

  • ACK支援GPU拓撲感知調度,可在節點的GPU組合中選擇具有最優訓練速度的組合。

  • 可將叢集中已指派但未使用的資源量化並提供給低優先順序任務使用,以實現動態資源超賣