Koordinator 最佳實踐系列:精細化 CPU 編排

介紹

在雲原生環境中,集羣提供者常常將不同類型的工作負載部署在同一個集羣中,利用不同業務的不同峯值效果,實現資源分時複用,避免資源浪費。然而,不同類型負載之間混合部署常常會導致資源競爭和相互干擾。最爲典型的場景便是在線和離線負載的混合部署。當離線較多的佔用計算資源時,在線負載的響應時間就會受到影響;當在線長時間較多的佔用計算資源時,離線負載的任務完成時間不能得到保證。這種現象屬於 Noisy Neighbor 問題。

根據混合部署的程度、資源類型的不同,解決該問題有許多不同的思路。Quota 管理可從整個集羣維度限制負載的資源使用量,Koordinator 在這方面提供了多層次彈性 Quota 管理功能[1]。單機維度上看,CPU、內存、磁盤 IO,網絡資源都有可能被不同負載共享。Koordinator 在 CPU、內存上已經提供了一些資源隔離和保障的能力,磁盤 IO 和網絡資源方面的相關能力正在建設中。

本文主要介紹當不同類型工作負載混合部署在同一個節點上時,Koordinator 如何幫助負載之間(在線和在線、在線和離線)協同地共享 CPU 資源。

問題描述

CPU 資源 Noisy Neighbor 的本質是不同的負載之間無協同地共享 CPU 資源。

  1. Kubernetes 默認的資源模型利用 cgroup(cfs quota) 從 CPU 時間使用量上來限制不同負載對於 CPU 資源的訪問。這種情況下,一些負載就可能會被操作系統調度器切換所在的 CPU 核。由於不同 CPU 覈對不同物理位置的內存訪問時間不同,切換大概率會導致更長的內存訪問時間,從而影響負載性能。
  2. 在 NUMA 架構中,SMT 線程(邏輯核)共享物理核的執行單元和 L2 緩存。當同一個物理核中有多種工作負載時,不同工作負載間就會產生資源爭搶,導致負載性能下降。

Kubernetes 在單機側提供了拓撲管理器和 CPU 管理器來嘗試解決上述問題。然而,該功能只有在 Pod 已經調度到機器上之後纔會嘗試生效。這樣就有可能導致 Pod 會被調度到 CPU 資源滿足但是 CPU 拓撲不滿足負載要求的情況。

解決方案

面向應用的 CPU 編排 QoS 語義

針對上述問題和不足,Koordinator 設計了面向應用的 QoS 語義和 CPU 編排協議,如下圖所示。

LS(Latency Sensitive)應用於典型的微服務負載,Koordinator 將其與其它的延遲敏感型負載隔離保障其性能。LSR(Latency Sensitive Reserved)類似於 Kubernetes 的 Guaranteed,在 LS 的基礎上增加了應用要求預留綁核的語義。LSE(Latency Sensitive Exclusive)則常見於中間件等對 CPU 特別敏感的應用,Koordinator 除了滿足其類似於 LSR 要求綁核的語義外,還確保其所被分配的 CPU 不與任何其它負載共享。

另外,爲提高資源利用率,BE 負載可與 LSR 和 LS 共享CPU。爲了確保與 BE 共享的延遲敏感型應用不受其干擾,Koordinator 提供瞭如干擾檢測、BE 壓制等策略。本文重點不在此,讀者可關注後續文章。

豐富的 CPU 編排策略

對於 LSE 類型的應用,當機器是超線程架構時,只能保證負載獨佔邏輯核。這樣當同一個物理核中有其它負載時,應用性能仍會受干擾。爲此,Koordinator 支持用戶在 Pod Annotation 上配置豐富的 CPU 編排策略來提高性能。

CPU 編排策略分爲 CPU 綁定策略和 CPU 獨佔策略。CPU 綁定策略決定應用所被分配邏輯核在物理核間的分佈,可採用物理核間打散或者堆疊。堆疊(FullPCPU)的方式指爲應用分配完整的物理內核,可以有效地緩解 Noisy Neighbor 問題。打散(SpreadByPCPU)則主要應用於一些具有多種不同峯谷特性的延遲敏感型應用,可以讓應用程序在特定時間充分使用 CPU。CPU 獨佔策略決定應用所被分配邏輯核的獨佔級別,可儘量避開已經同獨佔策略申請的物理核或 NUMANode。

增強的 CPU 調度能力

Koordinator 支持配置 NUMA 的分配策略,決定在調度時如何選擇滿意的 NUMA 節點。MostAllocated 表示從可用資源最少的 NUMA 節點分配,可以儘可能減少碎片,爲後續的負載留下更大的分配空間。但是,這種方式可能會導致依賴 Barrier 的並行代碼性能收到影響。DistributeEvenly 表示在 NUMA 節點上平均分配 CPU,可以提高上述並行代碼的性能。LeastAllocated 表示從可用資源最多的 NUMA 節點分配。

另外,Koordinator 對 CPU 的分配邏輯是在中心調度器完成的。這樣就會有一個全局的視角,避免了 Kubernetes 單機方案可能導致的 CPU 資源量滿足但是拓撲不滿足的窘境。

最佳實踐

由上文可知,Koordinator 精細化 CPU 編排能力能夠顯著提高多應用混合部署場景下 CPU 敏感型工作負載的性能。爲了讓讀者能夠更清楚地使用和直觀感受 Koordinator 的精細化 CPU 編排能力,本文將在線應用採用不同方式部署到集羣中,觀察壓測中服務的延遲,來判斷 CPU 編排能力的效果。

本文會在同一個機器上部署多個在線應用,壓測 10 分鐘,以充分模擬生產實踐中可能出現的 CPU 核切換場景。對於在線應用和離線應用混合部署的情況,Koordinator 提供瞭如干擾檢測、BE 壓制等策略。本文重點不在此,讀者可關注後續文章中的實踐。

本次實驗採用以下指標,評估應用不同部署方式下 Nginx 應用的性能表現:

  • 響應時間 RT(Response Time)分位值RT 是在線應用通常關注的性能指標,RT 越低代表在線服務性能越好。RT 指標通過收集 wrk 壓測結束後打印的信息獲得,在實驗中反映了 Nginx 應用響應 wrk 請求所花費的時間。例如 RT-p50 表示 Nginx 響應前 50% wrk 請求最大所花費的時間(中位數),RT-p90 表示 Nginx 響應前 90% wrk 請求最大所花費的時間。
  • 每秒請求數 RPS(Request Per Second)RPS 是在線應用每秒服務的請求數量,服務承受的 RPS 越多代表在線服務的性能越好。

實驗結果如下:

  • 對比 B 和 A,可以發現採用 LSE QoS 綁核之後,服務響應時間 P99 明顯減小,很好地減輕了長尾現象
  • 對比 C 和 B,可以發現採用 LSR QoS 綁核且允許邏輯核佔用更多物理覈資源之後,在服務響應時間更好的情況下可以承受更多的請求

綜上,在線服務部署在同一機器的場景下,採用 koordinator 精細化 CPU 編排能夠有效抑制 Noisy Neighbor 問題,減少 CPU 核切換帶來的性能下降。

環境

首先,要先準備一個 Kubernetes 集羣並安裝 Koordinator[2]。本文選擇一個 Kubernetes 集羣的兩個節點來做實驗,其中一個節點作爲測試機,將運行 Nginx 在線服務器;另一節點作爲壓測機,將運行客戶端的 wrk,向 Nginx 請求 Web 服務,製造壓測請求。

在線應用

1. 使用 ColocationProfile[3]爲應用注入精細化 CPU 編排協議

B 組精細化 CPU 編排協議:

apiVersion: config.koordinator.sh/v1alpha1
kind: ClusterColocationProfile
metadata:
  name: colocation-profile-example
spec:
  selector:
    matchLabels:
      app: nginx
  # 採用 LSE QoS
  qosClass: LSE
  annotations:
  # 採用物理核間堆疊
    scheduling.koordinator.sh/resource-spec: '{"preferredCPUBindPolicy":"FullPCPUs"}'
  priorityClassName: koord-prod

C 組 CPU 精細化編排協議:

apiVersion: config.koordinator.sh/v1alpha1
kind: ClusterColocationProfile
metadata:
  name: colocation-profile-example
spec:
  selector:
    matchLabels:
      app: nginx
  # 採用 LSR QoS
  qosClass: LSR
  annotations:
  # 採用物理核間打散且獨佔物理核
    scheduling.koordinator.sh/resource-spec: '{"preferredCPUBindPolicy":"SpreadByPCPUs", "preferredCPUExclusivePolicy":"PCPULevel"}'
  priorityClassName: koord-prod

2. 在線服務本文選用 Nginx 在線服務器,Pod YAML 如下:

---
# nginx應用配置
apiVersion: v1
data:
  config: |-
    user  nginx;
    worker_processes  4; # Nginx的Worker個數,影響Nginx Server的併發。

    events {
        worker_connections  1024;  # 默認值爲1024。
    }

    http {
        server {
            listen  8000;

            gzip off;
            gzip_min_length 32;
            gzip_http_version 1.0;
            gzip_comp_level 3;
            gzip_types *;
        }
    }

    #daemon off;
kind: ConfigMap
metadata:
  name: nginx-conf-0
---
# Nginx實例,作爲在線類型服務應用。
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: nginx
  name: nginx-0
  namespace: default
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - "${node_name}"    
  schedulerName: koord-scheduler
  priorityClassName: koord-prod
  containers:
    - image: 'koordinatorsh/nginx:v1.18-koord-exmaple'
      imagePullPolicy: IfNotPresent
      name: nginx
      ports:
        - containerPort: 8000
          hostPort: 8000 # 壓測請求訪問的端口。
          protocol: TCP
      resources:
        limits:
          cpu: '4'
          memory: 8Gi
        requests:
          cpu: '4'
          memory: 8Gi
      volumeMounts:
        - mountPath: /apps/nginx/conf
          name: config
  hostNetwork: true
  restartPolicy: Never
  volumes:
    - configMap:
        items:
          - key: config
            path: nginx.conf
        name: nginx-conf-0
      name: config

3. 執行以下命令,部署 Nginx 應用

kubectl apply -f nginx-0.yaml

4. 執行以下命令,查看 Nginx 應用的 Pod 狀態

kubectl get pod -l app=nginx -o wide

可以看到輸出如下,表示 Nginx 應用已經在測試機上正常運行

NAME      READY   STATUS    RESTARTS   AGE     IP           NODE                    NOMINATED NODE   READINESS GATES
nginx-0   1/1     Running   0          2m46s   10.0.0.246   cn-beijing.10.0.0.246   <none>           <none>

5. 在壓測機上,執行以下命令,部署壓測工具 wrk

wget -O wrk-4.2.0.tar.gz https://github.com/wg/wrk/archive/refs/tags/4.2.0.tar.gz && tar -xvf wrk-4.2.0.tar.gz
cd wrk-4.2.0 && make && chmod +x ./wrk

壓測

1. 使用壓測工具 wrk,向 Nginx 應用發起壓測請求。

# node_ip填寫測試機的IP地址,用於wrk向測試機發起壓測;8000是Nginx暴露到測試機的端口。
taskset -c 32-45 ./wrk -t120 -c400 -d600s --latency http://${node_ip}:8000/

2. 等待 wrk 運行結束後,獲取 wrk 的壓測結果,wrk 輸出格式如下所示。重複多次測試,以獲得相對穩定的結果。

Running 10m test @ http://192.168.0.186:8000/
  120 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.29ms    2.49ms 352.52ms   91.07%
    Req/Sec     0.96k   321.04     3.28k    62.00%
  Latency Distribution
     50%    2.60ms
     75%    3.94ms
     90%    5.55ms
     99%   12.40ms
  68800242 requests in 10.00m, 54.46GB read
Requests/sec: 114648.19
Transfer/sec:     92.93MB

總結

在 Kubernetes 集羣中,不同業務負載之間可能存在 CPU、內存等資源的爭搶,影響業務的性能和穩定性。面對 Noisy Neighbor 現象,用戶可以使用 Koordinator 爲應用配置更精細的 CPU 編排策略,使得不同應用可以協同的共享 CPU 資源。我們通過實驗說明,Koordinator 的精細化 CPU 編排能力能有效抑制 CPU 資源的爭搶,改善應用性能。

相關鏈接:

[1] 多層次彈性 Quota 管理功能

https://koordinator.sh/docs/user-manuals/multi-hierarchy-elastic-quota-management/

[2] 安裝 Koordinator

https://koordinator.sh/docs/installation/

[3] ColocationProfile

https://koordinator.sh/docs/user-manuals/colocation-profile/

作者:喬普、申信

點擊立即免費試用雲產品 開啓雲上實踐之旅!

原文鏈接

本文爲阿里雲原創內容,未經允許不得轉載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章