如何合理使用 CPU 管理策略,提升容器效能?

阿里巴巴雲原生發表於2022-02-24

作者:張佐瑋(佑禕)

前言

在雲原生時代下,應用工作負載都是以容器的形式部署在宿主機,共享各類物理資源。隨著宿主機硬體效能的增強,單節點的容器部署密度進一步提升,由此帶來的程式間 CPU 爭用,跨 NUMA 訪存等問題也更加嚴重,影響了應用效能表現。如何分配和管理宿主機的 CPU 資源,保障應用可以獲得最優的服務質量,是衡量容器服務技術能力的關鍵因素。

節點側容器 CPU 資源管理

Kubelet 的 CPU 分配策略

Kubernetes 為容器資源管理提供了 request(請求)和 limit(約束)的語義描述,當容器指定了 request 時,排程器會利用該資訊決定 Pod 應該被分配到哪個節點上;當容器指定了 limit 時,Kubelet 會確保容器在執行時不會超用。

CPU 是一種典型的分時複用型資源,核心排程器會將 CPU 分為多個時間片,輪流為各程式分配一定的執行時間。Kubelet 預設的 CPU 管理策略會通過 Linux 核心的 CFS 頻寬控制器(CFS Bandwidth Controller)來控制容器 CPU 資源的使用上限。在多核節點下,程式在執行過程中經常會被遷移到其不同的核心,考慮到有些應用的效能對 CPU 上下文切換比較敏感,Kubelet 還提供了 static 策略,允許 Guaranteed 型別 Pod 獨佔 CPU 核心。

核心 CPU 資源排程

核心 CFS 排程是通過 cfs_period 和 cfs_quota 兩個引數來管理容器 CPU 時間片消耗的,cfs_period 一般為固定值 100 ms,cfs_quota 對應容器的 CPU Limit。例如對於一個 CPU Limit = 2 的容器,其 cfs_quota 會被設定為 200ms,表示該容器在每 100ms 的時間週期內最多使用 200ms 的 CPU 時間片,即 2 個 CPU 核心。當其 CPU 使用量超出預設的 limit 值時,容器中的程式會受核心排程約束而被限流。細心的應用管理員往往會在叢集 Pod 監控中的 CPU Throttle Rate 指標觀察到這一特徵。

在這裡插入圖片描述

容器 CPU 效能問題現狀

讓應用管理員常常感到疑惑的是,為什麼容器的資源利用率並不高,但卻頻繁出現應用效能下降的問題?從 CPU 資源的角度來分析,問題通常來自於以下兩方面:一是核心在根據 CPU Limit 限制容器資源消耗時產生的 CPU Throttle 問題;二是受 CPU 拓撲結構的影響,部分應用對程式在 CPU 間的上下文切換比較敏感,尤其是在發生跨 NUMA 訪問時的情況。

CPU Throttle 問題詳解

受核心排程控制週期(cfs_period)影響,容器的 CPU 利用率往往具有一定的欺騙性,下圖展示了某容器一段時間的 CPU 使用情況(單位為0.01核),可以看到在 1s 級別的粒度下(圖中紫色折線),容器的 CPU 用量較為穩定,平均在 2.5 核左右。根據經驗,管理員會將 CPU Limit設定為 4 核。本以為這已經保留了充足的彈性空間,然而若我們將觀察粒度放大到 100ms 級別(圖中綠色折線),容器的 CPU 用量呈現出了嚴重的毛刺現象,峰值達到 4 核以上。此時容器會產生頻繁的 CPU Throttle,進而導致應用效能下降、RT 抖動,但我們從常用的 CPU 利用率指標中竟然完全無法發現!

在這裡插入圖片描述

毛刺產生的原因通常是由於應用突發性的 CPU 資源需求(如程式碼邏輯熱點、流量突增等),下面我們用一個具體的例子來描述 CPU Throttle 導致應用效能下降的過程。圖中展示了一個CPU Limit = 2 的 Web 服務類容器,在收到請求後(req)各執行緒(Thread)的 CPU 資源分配情況。假設每個請求的處理時間均為 60 ms,可以看到,即使容器在最近整體的 CPU 利用率較低,由於在 100 ms~200 ms 區間內連續處理了4 個請求,將該核心排程週期內的時間片預算(200ms)全部消耗,Thread 2 需要等待下一個週期才能繼續將 req 2 處理完成,該請求的響應時延(RT)就會變長。這種情況在應用負載上升時將更容易發生,導致其 RT 的長尾情況將會變得更為嚴重。

在這裡插入圖片描述

為了避免 CPU Throttle 的問題,我們只能將容器的 CPU Limit 值調大。然而,若想徹底解決 CPU Throttle,通常需要將 CPU Limit 調大兩三倍,有時甚至五到十倍,問題才會得到明顯緩解。而為了降低 CPU Limit 超賣過多的風險,還需降低容器的部署密度,進而導致整體資源成本上升。

CPU 拓撲結構的影響

在 NUMA 架構下,節點中的 CPU 和記憶體會被切分成了兩部分甚至更多(例如圖中 Socket0,Socket1),CPU 被允許以不同的速度訪問記憶體的不同部分,當 CPU 跨 Socket 訪問另一端記憶體時,其訪存時延相對更高。盲目地在節點為容器分配物理資源可能會降低延遲敏感應用的效能,因此我們需要避免將 CPU 分散繫結到多個 Socket 上,提升記憶體訪問時的本地性。如下圖所示,同樣是為兩個容器分配 CPU、記憶體資源,顯然場景B中的分配策略更為合理。

在這裡插入圖片描述

Kubelet 提供的 CPU 管理策略 “static policy”、以及拓撲管理策略 “single-numa-node”,會將容器與 CPU 繫結,可以提升應用負載與 CPU Cache,以及 NUMA 之間的親和性,但這是否一定能夠解決所有因 CPU 帶來的效能問題呢,我們可以看下面的例子。

某 CPU Limit = 2 的容器,其應用在 100ms 時間點收到了 4 個請求需要處理,在 Kubelet 提供的 static 模式下,容器會被固定在 CPU0 和 CPU1 兩個核心,各執行緒只能排隊執行,而在 Default 模式下,容器獲得了更多的 CPU 彈性,收到請求後各執行緒可以立即處理。可以看出,綁核策略並不是“銀彈”,Default 模式也有適合自己的應用場景。

在這裡插入圖片描述

事實上,CPU 綁核解決的是程式在不同 Core,特別是不同 NUMA 間上下文切換帶來的效能問題,但解決的同時也損失了資源彈性。在這種情況下執行緒會在各 CPU 排隊執行,雖然 CPU Throttle 指標可能有所降低,但應用自身的效能問題並沒有完全解決。

使用 CPU Burst 機制提升容器效能

往期文章我們介紹了阿里雲貢獻的 CPU Burst 核心特性,可以有效解決 CPU Throttle 的問題,當容器真實 CPU 資源使用小於 cfs_quota 時,核心會將多餘的 CPU 時間“存入”到 cfs_burst 中;當容器有突發的 CPU 資源需求,需要使用超出 cfs_quota 的資源時,核心的 CFS 頻寬控制器(CFS Bandwidth Controller,簡稱 BWC) 會允許其消費其之前存到 cfs_burst 的時間片。

在這裡插入圖片描述

CPU Burst 機制可以有效解決延遲敏感性應用的 RT 長尾問題,提升容器效能表現,目前阿里雲容器服務 ACK 已經完成了對 CPU Burst 機制的全面支援。對於尚未支援 CPU Burst 策略的核心版本,ACK 也會通過類似的原理,監測容器 CPU Throttle 狀態,並動態調節容器的 CPU Limit,實現與核心 CPU Burst 策略類似的效果。

我們使用 Apache HTTP Server 作為延遲敏感型線上應用,通過模擬請求流量,評估 CPU Burst 能力對響應時間(RT)的提升效果。以下資料分別展示了 CPU Burst 策略開啟前後的表現情況:

在這裡插入圖片描述

對比以上資料可得知:

  • 在開啟 CPU Burst 能力後,應用的 RT 指標的 p99 分位值得到了明顯的優化。
  • 對比 CPU Throttled 及利用率指標,可以看到開啟 CPU Burst 能力後,CPU Throttled 情況得到了消除,同時 Pod 整體利用率基本保持不變。

使用拓撲感知排程提升容器效能

雖然 Kubelet 提供了單機的資源管理策略(static policy,single-numa-node),可以部分解決應用效能表現受 CPU 快取、NUMA 親和性影響的問題,但該策略尚有以下不足之處:

  • static policy 只支援 QoS 為 Guaranteed 的 Pod,其他 QoS 型別的 Pod 無法使用
  • 策略對節點內所有 Pod 全部生效,而我們通過前面的分析知道,CPU 綁核並不是”銀彈“
  • 中心排程並不感知節點實際的 CPU 分配情況,無法在叢集範圍內選擇到最優組合

阿里雲容器服務 ACK 基於 Scheduling framework 實現了拓撲感知排程以及靈活的綁核策略,針對 CPU 敏感型的工作負載可以提供更好的效能。ACK 拓撲感知排程可以適配所有 QoS 型別,並支援在 Pod 維度按需開啟,同時可以在全叢集範圍內選擇節點和 CPU 拓撲的最優組合。

通過對 Nginx 服務進行的評測,我們發現在 Intel(104核)、AMD(256核)的物理機上,使用 CPU 拓撲感知排程能夠將應用效能提升 22%~43%。

在這裡插入圖片描述

總結

CPU Burst、拓撲感知排程是阿里雲容器服務 ACK 提升應用效能的兩大利器,它們解決了不同場景下的 CPU 資源管理,可以共同使用。

CPU Burst 解決了核心 BWC 排程時針對 CPU Limit 的限流問題,可以有效提升延時敏感型任務的效能表現。但 CPU Burst 本質並不是將資源無中生有地變出來,若容器 CPU 利用率已經很高(例如大於50%),CPU Burst 能起到的優化效果將會受限,此時應該通過 HPA 或 VPA 等手段對應用進行擴容。

拓撲感知排程降低了工作負載 CPU 上下文切換的開銷,特別是在 NUMA 架構下,可以提升 CPU 密集型,訪存密集型應用的服務質量。不過正如前文中提到的,CPU 綁核並不是“銀彈”,實際效果取決於應用型別。此外,若同一節點內大量 Burstable 型別 Pod 同時開啟了拓撲感知排程,CPU 綁核可能會產生重疊,在個別場景下反而會加劇應用間的干擾。因此,拓撲感知排程更適合針對性的開啟。

點選此處,即可檢視阿里雲 ACK 支援 CPU Burst 、拓撲感知排程的詳細介紹!

相關文章