Linux 進程管理之 CFS 負載均衡

什麼是負載均衡?

前面的調度學習都是默認在單個 CPU 上的調度策略。我們知道爲了 CPU 之間減少 “干擾”,每個 CPU 上都有一個任務隊列。運行的過程種可能會出現有的 CPU“忙的一筆”,有的 CPU“閒的蛋疼”,於是便需要負載均衡。

將 task 從負載較重的 CPU 上轉移到負載相對較輕的 CPU 上執行,這個過程就是負載均衡的過程。

在瞭解負載均衡前有必要了解 soc 上對 CPU 的拓撲關係。

我們知道一個多核心的 soc 片上系統,內部結構是很複雜的,內核採用 CPU 拓撲結構來描述一個 SOC 的架構。內核使用調度域來描述 CPU 之間的層次關係,對於低級別的調度域來說,CPU 之間的負載均衡處理開銷比較小,而對於越高級別的調度域,其負載均衡的開銷就越大。

比如一個 4 核心的 SOC,兩個核心是一個 cluster,共享 L2 cache,那麼每個 cluster 可以認爲是一個 MC 調度域,每個 MC 調度域中有兩個調度組,每個調度組中只有一個 CPU。而整個 SOC 可以認爲是高一級別的 DIE 調度域,其中有兩個調度組,cluster0 屬於一個調度組,cluster1 屬於另一個調度組。跨 cluster 的負載均衡是需要清除 L2 cache 的,開銷是很大的,因此 SOC 級別的 DIE 調度域進行負載均衡的開銷會更大一些。

CPU 對應的調度域和調度組可通過在設備模型文件 /proc/sys/kernel/sched_domain 裏查看。

3n2MyU

9GtlZ8

CPU 拓撲示例

爲了減少鎖的競爭,每一個 cpu 都有自己的 MC domain、DIE domain(sched domain 是分成兩個 level,base domain 稱爲 MC domain(multi core domain),頂層的 domain 稱爲 DIE domain)以及 sched group,並且形成了 sched domain 之間的層級結構,sched group 的環形鏈表結構。可以通過 / sys/devices/system/cpu/cpuX/topology 查看 cpu topology 信息。

在上面的結構中,sched domain 是分成兩個 level,base domain 稱爲 MC domain,頂層的 domain 稱爲 DIE domain。頂層的 DIE domain 覆蓋了系統中所有的 CPU,小核 cluster 的 MC domain 包括所有小核 cluster 中的 cpu,大核 cluster 的 MC domain 包括所有大核 cluster 中的 cpu。

通過 DTS 和 CPU topo 子系統,可以構建 sched domain 層級結構,用於具體的均衡算法。流程是:kernel_init() -> kernel_init_freeable() -> smp_prepare_cpus() -> init_cpu_topology() -> parse_dt_topology()

負載均衡的軟件架構

圖中可以看出左邊主要分爲 CPU 負載跟蹤和 task 負載跟蹤。

右邊是通過 DTS 和 CPU topo 子系統,構建的 sched domain 層級結構。流程是:kernel_init() -> kernel_init_freeable() -> smp_prepare_cpus() -> init_cpu_topology() -> parse_dt_topology()

有了左右兩邊的基礎設施,那麼什麼時候觸發負載均衡呢?這主要和調度事件相關,當發生任務喚醒、任務創建、tick 到來等調度事件的時候,就可以檢查當前系統的不均衡情況,並酌情進行任務遷移,以便讓系統負載處於平衡狀態。

何時做負載均衡?

CFS 任務的負載均衡器有兩種。一種是爲繁忙 CPU 們準備的 periodic balancer,用於 CFS 任務在 busy cpu 上的均衡;一種是爲 idle cpu 們準備的 idle balancer,用於把繁忙 CPU 上的任務均衡到 idle cpu 上來。

  1. 週期性負載均衡(periodic load balance 或者 tick load balance)是指在 tick 中,週期性的檢測系統的負載均衡狀況,找到系統中負載最重的 domain、group 和 CPU,將其上的 runnable 任務拉到本 CPU 以便讓系統的負載處於均衡的狀態。

  1. nohz load balance 是指其他的 cpu 已經進入 idle,本 CPU 任務太重,需要通過 IPI 將其他 idle 的 CPUs 喚醒來進行負載均衡。nohz idle load balance 也是通過 busy cpu 上 tick 驅動的,如果需要 kick idle load balancer,那麼就會通過 GIC 發送一個 ipi 中斷給選中的 idle cpu,讓它代表系統所有的 idle cpu 們進行負載均衡。

  1. new idle load balance 比較好理解,就是在 CPU 上沒有任務執行,馬上要進入 idle 狀態的時候,看看其他 CPU 是否需要幫忙,來從 busy cpu 上拉任務,讓整個系統的負載處於均衡狀態。

負載均衡的基本過程

當一個 CPU 上進行負載均衡的時候,總是從 base domain 開始,檢查其所屬 sched group 之間的負載均衡情況,如果有不均衡情況,那麼會在該 cpu 所屬 cluster 之間進行遷移,以便維護 cluster 內各個 cpu core 的任務負載均衡。

load_balance 是處理負載均衡的核心函數,它的處理單元是一個調度域,也就是 sched domain,其中會包含對調度組的處理。

  1. 在該 domain 中找到最忙的 sched group

  2. 在最忙的 group 中挑選最忙的 CPU runqueue,該 CPU 就成爲任務遷移的 src

  3. 從該隊列中選擇要遷移的任務(判斷的依據主要是 task load 的大小,優先選擇 load 重的任務)

  4. 向着作爲 dst 的 CPU runqueue 遷移

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/w3sR3ag-YyZ-ZrzdO8P8rw