/

理解 Kubernetes 中的 CPU Limit

TL;DR

Kubernetes 中的資源限制目前可以對兩種資源做限制,分別為 cpu(可壓縮資源), memory(不可壓縮資源)。針對這兩種資源的限制可以對應到兩種限制,分別為 Soft Limit(request)與 Hard Limit(limit)

cgroup 對於這兩種資源達到 Hard Limit 的處理並不相同。記憶體超出 Hard Limit 會觸發 OOM;CPU 超出 Hard Limit 則是會造成 CPU Throttling(程式並不會被終止)

在 Cgroup 中使用針對 K8s Pod yaml 所定義之 Soft Limit:

1
spec.containers[].resources.requests.memory

會讓 Cgroup 設定系統之 cpu.shares 參數

而 Hard Limit:

1
spec.containers[].resources.requests.cpu

會讓 Cgroup 設定系統之 cpu.cfs_period_us, cpu.cfs_quota_us 參數

cpu.shares

當我們在 Pod 之 yaml 中定義 spec.containers[].resources.requests.cpu

1
2
3
4
5
6
7
8
9
10
spec:
containers:
- name: busybox
image: hwchiu/netutils
args:
- sleep
- infinity
resources:
requests:
cpu: "500m"

可以從對應節點的路徑發現各種 cgroup 參數

/sys/fs/cgroup/cpu,cpuacct/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod.slice

(因為只有設定 request 所以是進入 burstable 目錄,關於 Pod QoS 可以參考 Kubernetes 官方文件)

此時可以發現

檔案:cpu.cfs_quota_us 的內容為 -1(因為沒有設定 Hard Limit,-1 代表不受限制),而 cpu.shares 的內容為 512(與設定的 500m 不相同是因為 cgroup 以 1024 為底,yaml 以 1000 為底)

而這個 512 會讓該 Pod(以下稱為 Pod A)具有

512 / (512 + Other Pod cpu.shares) 的 CPU 使用時間

假設叢集中只有兩個 Pod,另外一個 Pod 的 cpu.shares 為 1024

則 Pod A 的使用時間有

512/(512 + 1024) = 33%

這種相對的設定方式很明顯的可以發現並沒有辦法實質控制 Pod 在 CPU 的時間分配

cpu.cfs_quota_us

然而如果設定的 Pod yaml 為:

1
2
3
4
5
resources:
requests:
cpu: "500m"
limits:
cpu: "900m"

可以發現 cpu.cfs_period_us 的值為 100000,以及 cpu.cfs_quota_us 的值為 90000

100000 的含義代表 CPU 一個週期,也就是 1/10 秒(100000 微秒)

90000 代表在這個週期內,該 Pod 最高可以使用的時間為 90000 微秒,也就是 yaml 中設定的 900m

換句說話,如果我們要讓 Pod 在一個 CPU 週期可以完全跑滿,那就要設定 1000m

如果使用到上限,程式還沒結束,該 CPU 週期內的該程式就會被 Throttling,留到下一個週期才能繼續執行

但是一但設定了 Hard Limit 同時代表系統上的 CPU 不忙碌,該 Pod 也無法使用更多的 CPU 時間

參考資料