預設情況下,kubelet 使用CFS配額來執行 Pod 的 CPU 約束。Kubernetes的Node節點會執行多個Pod,其中會有部分的Pod屬於CPU密集型的工作負載。在這種情況下,Pod之間會爭搶節點的CPU資源。當爭搶劇烈的時候,Pod會在不同的CPU Core之間進行頻繁的切換,更糟糕的是在NUMA Node之間的切換。這種大量的上下文切換,會影響程式執行的效能。
什麼是cpu密集型?
通俗來講就是對cpu依賴很高,操作cpu的頻率非常高,充分的使用cpu資源來實現本地計算任務。
另外還有io密集型:
io密集型就是講磁碟/記憶體的io操作會非常頻繁,檔案讀寫、網路請求等,這種一般cpu利用率會非常低
CPU Manager特性是節點級別的CPU排程選擇,所以無法在叢集維度中選擇最優的CPU Core組合。同時CPU Manager特性要求Pod是Guaranteed時(Pod中的每個容器必須指定CPU Request和CPU Limit,並且兩者要相等)才能生效,且無法適用於所有型別的Pod。
cpu Manager 在 Kubernetes v1.12 參照為 [beta],故想要更好的使用它,版本需>=v1.12。
CPU 管理策略通過 kubelet 引數 --cpu-manager-policy 或 KubeletConfiguration 中的 cpuManagerPolicy 欄位來指定。支援兩種策略:
none 策略顯式地啟用現有的預設 CPU 親和方案,不提供作業系統排程器預設行為之外的親和性策略。通過 CFS 配額來實現 Guaranteed Pods和 Burstable Pods的 CPU 使用限制。
static 策略針對具有整數型 CPU requests 的 Guaranteed Pod ,它允許該類 Pod中的容器存取節點上的獨佔 CPU 資源。這種獨佔性是使用cpuset cgroup 控制器來實現的。
CPU 管理器定期通過 CRI 寫入資源更新,以保證記憶體中 CPU 分配與 cgroupfs 一致。同步頻率通過新增的 Kubelet 設定引數 --cpu-manager-reconcile-period 來設定。如果不指定,預設與 --node-status-update-frequency 的週期(預設10s)相同。
Static 策略的行為可以使用 --cpu-manager-policy-options 引數來微調。該引數採用一個逗號分隔的 key=value 策略選項列表。此特性可以通過 CPUManagerPolicyOptions 特性門控來完全禁用。
由於 CPU 管理器策略只能在 kubelet 生成新 Pod 時應用,所以簡單地從 "none" 更改為 "static"將不會對現有的 Pod 起作用。因此,為了正確更改節點上的 CPU 管理器策略,請執行以下步驟:
說明: CPU 管理器不支援執行時下線和上線 CPUs。此外,如果節點上的 CPUs 集合發生變化,則必須驅逐節點上的 Pod,並通過刪除 kubelet 根目錄中的狀態檔案cpu_manager_state來手動重置 CPU Manager。
此策略管理一個 CPU 共用池,該共用池最初包含節點上所有的 CPU 資源。可獨佔性 CPU 資源數量等於節點的 CPU 總量減去通過 kubelet --kube-reserved 或 --system-reserved引數保留的 CPU 資源。從 1.17 版本開始,可以通過 kubelet --reserved-cpus 引數顯式地指定 CPU 預留列表。由 --reserved-cpus 指定的顯式 CPU 列表優先於由 --kube-reserved 和 --system-reserved指定的 CPU 預留。通過這些引數預留的 CPU 是以整數方式,按物理核心 ID 升序從初始共用池獲取的。共用池是 BestEffort 和 Burstable Pod 執行的 CPU 集合。Guaranteed Pod 中的容器,如果宣告了非整數值的 CPU requests,也將執行在共用池的 CPU 上。只有 Guaranteed Pod 中,指定了整數型 CPU requests 的容器,才會被分配獨佔 CPU 資源。
說明: 當啟用 static 策略時,要求使用 --kube-reserved 和/或 --system-reserved 或--reserved-cpus 來保證預留的 CPU 值大於零。這是因為零預留 CPU 值可能使得共用池變空。
例如:--kube-reserved=cpu=1,memory=0
當 Guaranteed Pod 排程到節點上時,如果其容器符合靜態分配要求,相應的 CPU 會被從共用池中移除,並放置到容器的 cpuset 中。因為這些容器所使用的 CPU 受到排程域本身的限制,所以不需要使用 CFS 配額來進行 CPU 的繫結。換言之,容器 cpuset 中的 CPU 數量與 Pod 規約中指定的整數型 CPU limit 相等。這種靜態分配增強了 CPU 親和性,減少了 CPU 密集的工作負載在節流時引起的上下文切換。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
requests:
memory: "200Mi"
cpu: "2"
該 Pod 屬於 Guaranteed QoS 型別,因為其 requests 值與 limits相等。同時,容器對 CPU 資源的限制值是一個大於或等於 1 的整數值。所以,該 nginx 容器被賦予 2 個獨佔 CPU。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
該 Pod 屬於 Guaranteed QoS 型別,因其指定了 limits 值,同未指定requests,requests 值被設定為與 limits 值相等。同時,容器對 CPU 資源的限制值是一個大於或等於 1 的整數值。所以,該 nginx 容器被賦予 2 個獨佔 CPU。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "1.5"
requests:
memory: "200Mi"
cpu: "1.5"
該 Pod 屬於 Guaranteed QoS 型別,因為其 requests 值與 limits相等。但是容器對 CPU 資源的限制值是一個小數。所以該容器執行在共用 CPU 池中。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
requests:
memory: "100Mi"
cpu: "1"
該 Pod 屬於 Burstable QoS 型別,因為其資源 requests 不等於 limits。所以該容器執行在共用 CPU 池中。
你可以使用以下特性門控根據成熟度級別開啟或關閉選項組:
必須使用CPUManagerPolicyOptions kubelet 選項啟用某個選項。
靜態 CPUManager 策略存在以下策略選項:
如果使用 full-pcpus-only 策略選項,static 策略總是會分配完整的物理核心。預設情況下,如果不使用該選項,static 策略會使用拓撲感知最適合的分配方法來分配 CPU。在啟用了 SMT 的系統上,此策略所分配是與硬體執行緒對應的、獨立的虛擬核。這會導致不同的容器共用相同的物理核心,該行為進而會導致吵鬧的鄰居問題。
啟用該選項之後,只有當一個 Pod 裡所有容器的 CPU 請求都能夠分配到完整的物理核心時,kubelet 才會接受該 Pod。如果 Pod 沒有被准入,它會被置於 Failed 狀態,錯誤訊息是SMTAlignmentError。
如果使用 distribute-cpus-across-numa 策略選項,在需要多個 NUMA 節點來滿足分配的情況下,static 策略會在 NUMA 節點上平均分配 CPU。預設情況下,CPUManager 會將 CPU 分配到一個 NUMA 節點上,直到它被填滿,剩餘的 CPU 會簡單地溢位到下一個 NUMA 節點。這會導致依賴於同步屏障(以及類似的同步原語)的並行程式碼出現不期望的瓶頸,因為此類程式碼的執行速度往往取決於最慢的工作執行緒(由於至少一個 NUMA 節點存在可用 CPU 較少的情況,因此速度變慢)。通過在 NUMA 節點上平均分配 CPU,應用程式開發人員可以更輕鬆地確保沒有某個工作執行緒單獨受到 NUMA 影響,從而提高這些型別應用程式的整體效能。
可以通過將 full-pcups-only=true 新增到 CPUManager 策略選項來啟用 full-pcpus-only 選項。同樣地,可以通過將 distribute-cpus-across-numa=true新增到 CPUManager 策略選項來啟用 distribute-cpus-across-numa 選項。當兩者都設定時,它們是「累加的」,因為 CPU 將分佈在 NUMA 節點的 full-pcpus 塊中,而不是單個核心。