全部產品
Search
文件中心

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

更新時間:Jun 19, 2024

ACK基於新版的Scheduling framework實現CPU拓撲感知調度,針對CPU敏感型的工作負載提供更好的效能。本文介紹如何使用CPU拓撲感知調度。

原理介紹

Kubernetes的節點會運行多個Pod,其中部分Pod屬於CPU密集型工作負載。在這種情況下,Pod之間會爭搶節點的CPU資源。當爭搶劇烈時,Pod會在不同的CPU Core之間進行頻繁的切換,更糟糕的是在NUMA Node之間切換。這種大量的環境切換,會影響程式啟動並執行效能。Kubernetes雖然有CPU Manager解決方案處理以上問題,但是因為CPU Manager特性是節點層級的CPU調度選擇,所以無法在叢集維度中選擇最優的CPU Core組合。同時CPU Manager特性要求Pod是Guaranteed時(Pod中的每個容器必須指定CPU請求和CPU限制,並且兩者要相等)才會生效,且無法適用於所有類型的Pod。

在以下情境中,建議使用CPU拓撲感知調度:

  • 工作負載為計算密集型。

  • 應用程式對CPU敏感。

  • 運行在神龍裸金屬(Intel、AMD)等多核機器上。

    通過在物理機上部署兩個4核8 GB的Nginx並進行壓測,發現在Intel(104核)、AMD(256核)的物理機上,使用CPU拓撲感知調度能夠將應用效能提升22%~43%。具體如以下兩個圖所示:12

    效能指標

    Intel

    AMD

    QPS

    提升22.9%

    提升43.6%

    AVG RT

    下降26.3%

    下降42.5%

    重要

    不同應用對CPU綁核的敏感程度存在差異,上述實驗中的資料僅供參考,建議您將應用部署在穩定的環境中,根據機型等環境情況適當調節實驗壓力水位,確保應用運行正常,並在充分對比效能情況後評估是否開啟CPU拓撲感知調度功能。

在啟用CPU拓撲感知調度時,可通過在所建立Deployment對象的template.metadata.annotations(或者Pod對象的metadata.annotations)下,設定cpu-policystatic-burst,從而控制自動綁核策略。該策略能夠對計算密集性負載,有效避免進程的物理核心爭用及跨片記憶體訪問,最大化利用片段化CPU,在不改變硬體及虛擬機器資源的前提下為密集計算型負載最佳化可用資源,進一步提升CPU使用率。

關於CPU拓撲感知調度的實現原理,請參見Practice of Fine-grained Cgroups Resources Scheduling in Kubernetes

前提條件

  • 已建立ACK Pro版叢集。具體操作,請參見建立ACK Pro版叢集

  • 已安裝ack-koordinator(原ack-slo-manager)。具體操作,請參見ack-koordinator

    說明

    ack-koordinator在原resource-controller組件的基礎上做了升級最佳化,如果您正在使用resource-controller,需在安裝ack-koordinator後,卸載resource-controller。關於卸載的具體操作,請參見resource-controller

使用限制

系統組件版本要求具體如下表所示。

組件

版本要求

Kubernetes

≥v1.18

ack-koordinator

≥0.2.0

費用說明

ack-koordinator組件本身的安裝和使用是免費的,不過需要注意的是,在以下情境中可能產生額外的費用:

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

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

注意事項

  • 在使用CPU拓撲感知調度前,請保證已部署組件ack-koordinator。

  • 在使用CPU拓撲感知調度時,請保證節點的cpu-policy=none

  • 若需要限制應用的調度,請使用nodeSelector欄位。

    重要

    請不要使用nodeName欄位,該方式將無法進入調度器邏輯使用CPU拓撲感知調度。

使用CPU拓撲感知調度

啟用CPU拓撲感知調度前,您需要在提交Pod時設定annotationsContainers的值。具體操作步驟如下:

  • 在Deployment對象的template.metadata.annotations(或者在Pod對象的metadata.annotations)下,設定cpuset-schedulertrue,啟用CPU拓撲感知調度。

  • Containers下,設定resources.limit.cpu的值,且該值為整數。

  1. 使用以下模板建立go-demo.yaml檔案,在Deployment中使用CPU拓撲感知調度。

    重要
    • 針對Deployment對象,您需要在template.metadata下配置Pod的annotations

    • 在配置CPU拓撲感知調度時,可通過在annotations下設定cpu-policystatic-burst,從而控制自動綁核策略。需要配置時,請刪除cpu-policy前的#

    展開查看YAML檔案內容

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: go-demo
    spec:
      replicas: 4
      selector:
        matchLabels:
          app: go-demo
      template:
        metadata:
          annotations:
            cpuset-scheduler: "true" #表示CPU拓撲感知調度。
          labels:
            app: go-demo
        spec:
          containers:
          - name: go-demo
            image: registry.cn-hangzhou.aliyuncs.com/polinux/stress/go-demo:1k
            imagePullPolicy: Always
            ports:
            - containerPort: 8080
            resources:
              requests:
                cpu: 1
              limits: 
                cpu: 4  #需要設定resources.limit.cpu值。
  2. 執行以下命令,建立Deployment。

    kubectl create -f go-demo.yaml

驗證CPU拓撲感知對應用效能的提升

本樣本使用情境為:

  • ACK Pro版叢集版本為1.20。

  • 需要包含兩個節點:一台壓測機、一台測試機。

重要

以下部署和壓測命令僅供參考,您可結合自身實驗環境調節資源規格和請求壓力,確保應用處於正常工作狀態後再進行實驗。

  1. 執行以下命令,為測試機打上標籤。

     kubectl label node 192.168.XX.XX policy=intel/amd
  2. 在測試機上部署Nginx服務。

    1. 使用以下YAML樣本,建立Nginx服務組態檔。

      展開查看service.yaml檔案內容

      apiVersion: v1
      kind: Service
      metadata:
        name: nginx-service-nodeport
      spec:
        selector:
            app: nginx
        ports:
          - name: http
            port: 8000
            protocol: TCP
            targetPort: 80
            nodePort: 32257
        type: NodePort

      展開查看configmap.yaml檔案內容

      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: nginx-configmap
      data:
        nginx_conf: |-
          user  nginx;
          worker_processes  4;
          error_log  /var/log/nginx/error.log warn;
          pid        /var/run/nginx.pid;
          events {
              worker_connections  65535;
          }
          http {
              include       /etc/nginx/mime.types;
              default_type  application/octet-stream;
              log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                            '$status $body_bytes_sent "$http_referer" '
                            '"$http_user_agent" "$http_x_forwarded_for"';
              access_log  /var/log/nginx/access.log  main;
              sendfile        on;
              #tcp_nopush     on;
              keepalive_timeout  65;
              #gzip  on;
              include /etc/nginx/conf.d/*.conf;
          }

      展開查看nginx.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"    預設情況,不使用CPU拓撲感知調度。
            labels:
              app: nginx
          spec:
            nodeSelector:
              policy: intel7
            containers:
            - name: nginx
              image: nginx:latest
              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. 執行以下命令,建立Nginx服務。

      • kubectl create -f service.yaml
      • kubectl create -f configmap.yaml
      • kubectl create -f nginx.yaml
  3. 登入壓測機,下載wrk2開源測試載入器並解壓安裝。具體操作,請參見wrk2官方網站

    說明

    關於如何登入到節點,請參見使用VNC登入執行個體通過密碼認證登入Windows執行個體

  4. 執行以下命令,在壓測機上進行測試並記錄資料。

    wrk --timeout 2s -t 20 -c 100 -d 60s --latency http://<測試機IP>:32257

    預期輸出:

    20 threads and 100 connections
    Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   600.58us    3.07ms 117.51ms   99.74%
    Req/Sec    10.67k     2.38k   22.33k    67.79%
    Latency Distribution
    50%  462.00us
    75%  680.00us
    90%  738.00us
    99%    0.90ms
    12762127 requests in 1.00m, 10.10GB read
    Requests/sec: 212350.15Transfer/sec:    172.13MB
  5. 執行以下命令,刪除已部署的Nginx。

    kubectl delete deployment nginx

    預期輸出:

    deployment "nginx" deleted
  6. 使用以下YAML樣本,部署開啟CPU拓撲感知調度的Nginx。

    展開查看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"
          labels:
            app: nginx
        spec:
          nodeSelector:
            policy: intel7
          containers:
          - name: nginx
            image: nginx:latest
            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
  7. 執行以下命令,在壓測機上進行測試並記錄資料進行對比。

    wrk --timeout 2s -t 20 -c 100 -d 60s --latency http://<測試機IP>:32257

    預期輸出:

    20 threads and 100 connections
    ls  Thread Stats   Avg         Stdev     Max       +/- Stdev
    Latency            345.79us    1.02ms    82.21ms   99.93%
    Req/Sec            15.33k      2.53k     25.84k    71.53%
    Latency Distribution
    50%  327.00us
    75%  444.00us
    90%  479.00us
    99%  571.00us
    18337573 requests in 1.00m, 14.52GB read
    Requests/sec: 305119.06Transfer/sec:    247.34MB

    通過兩次資料的對比可以看出,開啟CPU拓撲感知調度後,Nginx的效能提升43%。

驗證自動綁核策略對應用效能的提升

本樣本介紹在一個64核的節點上設定CPU Policy。在設定控制自動綁核策略後,相比於CPU拓撲感知調度一般可以提升7%~8%的CPU使用效率。

重要

以下部署和壓測命令僅供參考,您可結合自身實驗環境調節資源規格,確保應用處於正常工作狀態後再進行實驗。

  1. 執行以下命令,查看Pod。

    kubectl get pods | grep cal-pi

    預期輸出:

    NAME                 READY     STATUS    RESTARTS   AGE
    cal-pi-d****         1/1       Running   1          9h
  2. 執行以下命令,查看應用cal-pi-d****的日誌。

    kubectl logs cal-pi-d****

    預期輸出:

    computing Pi with 3000 Threads...computed the first 20000 digets of pi in 620892 ms! 
    the first digets are: 3.14159264
    writing to pi.txt...
    finished!
  3. 使用CPU拓撲感知調度。

    在Deployment中使用CPU拓撲感知調度並控制自動綁核策略。更多資訊,請參見使用CPU拓撲感知調度

    1. 使用以下模板建立go-demo.yaml檔案,在Deployment中使用CPU拓撲感知調度。

      重要

      針對Deployment對象,您需要在template.metadata下配置Pod的annotations

      展開查看YAML檔案內容

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: go-demo
      spec:
        replicas: 4
        selector:
          matchLabels:
            app: go-demo
        template:
          metadata:
            annotations:
              cpuset-scheduler: "true" #表示CPU拓撲感知調度。
              cpu-policy: 'static-burst' #控制自動綁核策略,提升CPU片段利用率。
            labels:
              app: go-demo
          spec:
            containers:
            - name: go-demo
              image: registry.cn-hangzhou.aliyuncs.com/polinux/stress/go-demo:1k
              imagePullPolicy: Always
              ports:
              - containerPort: 8080
              resources:
                requests:
                  cpu: 1
                limits: 
                  cpu: 4  #需要設定resources.limit.cpu值。
    2. 執行以下命令,建立Deployment。

      kubectl create -f go-demo.yaml
  4. 執行以下命令,查看Pod。

    kubectl get pods | grep go-demo

    預期輸出:

    NAME                 READY     STATUS    RESTARTS   AGE
    go-demo-e****        1/1       Running   1          9h
  5. 執行以下命令,查看應用go-demo-e****的日誌。

    kubectl logs go-demo-e****

    預期輸出:

    computing Pi with 3000 Threads...computed the first 20000 digets of pi in 571221 ms!
    the first digets are: 3.14159264
    writing to pi.txt...
    finished!

    通過與步驟2的日誌資料對比,設定CPU Policy後Pod的效能提升8%。

相關文檔

Kubernetes對節點的GPU拓撲資訊不感知,調度過程中對GPU的選擇比較隨機,選擇不同的GPU組合訓練速度會存在較大的差異。基於以上問題,ACK基於Scheduling Framework機制,實現GPU拓撲感知調度,在節點的GPU組合中選擇具有最優訓練速度的組合。詳細資料,請參見GPU拓撲感知調度