玩轉 Cgroup 系列之三:挑戰手動管理 Cgroup

小猿姐聊技術發表於2023-12-28

在前面的文章中,作者討論了 Cgroup 和 CPUShare 如何用於系統管理和效能調優。

在這一篇文章中,作者將重點介紹 Cgroup 的手動管理任務。雖然手動管理 Cgroup 不是一件容易的事,但瞭解其中的過程可以幫助我們更好地認識 Cgroup 和資源管理。

挑戰手動管理 Cgroup

來看看如何在沒有相關工具支援的情況下建立 Cgroup。

本質上, Cgroup 只是一個掛載有  cgroups 的目錄結構,可以位於檔案系統的任何位置。在預設情況下,我們可以在  /sys/fs/cgroup 中找到系統建立的 Cgroup。而如果想手動建立 Cgroup 該怎麼做呢?首先,需要建立一個目錄:

# mkdir -p /my_cgroups

建立後,需要決定使用哪些控制器。注意,Cgroup v1 版本的結構大致如下:

/my_cgroups
├── <controller type>
│   ├── <group 1>
│   ├── <group 2>
│   ├── <group 3>

要建立的所有組都單獨巢狀在每個控制器下。因此,控制器  memory 下的  group1 與控制器  blkio 下的  group1 是完全獨立的。在這個基礎上,我們建立一個基本的 CPUShares 示例。 簡單起見,我先在系統上生成一些負載:

# cat /dev/urandom

這一步會在系統中產生一些人為負載,以便進行簡單測算。它不是一個真實的負載示例,但是突出了 CPUShares 的主要特點。我還設定了一臺執行 CentOS 8 的虛擬機器,只有一個 vCPU,以便進行非常簡單的數學計算。做好這些準備之後,第一步就是為我們的 Cgroup 控制器建立一些目錄:

# mkdir -p /my_cgroups/{memory,cpusets,cpu}

接下來,將 Cgroup 掛載到這些資料夾中:

# mount -t cgroup -o memory none /my_cgroups/memory
# mount -t cgroup -o cpu,cpuacct none /my_cgroups/cpu
# mount -t cgroup -o cpuset none /my_cgroups/cpusets

如果想建立自己的 Cgroup,只需在您想要使用的控制器下建立一個新的目錄就可以了。在這個例子中,我處理的是位於 cpu 目錄中的檔案  cpu.shares。下面我們在  cpu 控制器下建立一些 Cgroup:

# mkdir -p /my_cgroups/cpu/{user1,user2,user3}

請注意,這些目錄是由控制器自動填充的:

ls -l /my_cgroup/cpu/user1/
-rw-r--r--. 1 root root 0 Sep  5 10:26 cgroup.clone_children
-rw-r--r--. 1 root root 0 Sep  5 10:26 cgroup.procs
-r--r--r--. 1 root root 0 Sep  5 10:26 cpuacct.stat
-rw-r--r--. 1 root root 0 Sep  5 10:26 cpuacct.usage
-r--r--r--. 1 root root 0 Sep  5 10:26 cpuacct.usage_all
-r--r--r--. 1 root root 0 Sep  5 10:26 cpuacct.usage_percpu
-r--r--r--. 1 root root 0 Sep  5 10:26 cpuacct.usage_percpu_sys
-r--r--r--. 1 root root 0 Sep  5 10:26 cpuacct.usage_percpu_user
-r--r--r--. 1 root root 0 Sep  5 10:26 cpuacct.usage_sys
-r--r--r--. 1 root root 0 Sep  5 10:26 cpuacct.usage_user
-rw-r--r--. 1 root root 0 Sep  5 10:26 cpu.cfs_period_us
-rw-r--r--. 1 root root 0 Sep  5 10:26 cpu.cfs_quota_us
-rw-r--r--. 1 root root 0 Sep  5 10:26 cpu.rt_period_us
-rw-r--r--. 1 root root 0 Sep  5 10:26 cpu.rt_runtime_us
-rw-r--r--. 1 root root 0 Sep  5 10:20 cpu.shares
-r--r--r--. 1 root root 0 Sep  5 10:26 cpu.stat
-rw-r--r--. 1 root root 0 Sep  5 10:26 notify_on_release
-rw-r--r--. 1 root root 0 Sep  5 10:23 tasks

現在我已經設定了一些 Cgroup,然後就可以生成負載了。開啟三個 SSH 會話,並在前臺執行以下命令:

# cat /dev/urandom

可以在  top 中看到結果:


注意: CPUShares 是基於父級 Cgroup 的。預設情況下,父級 Cgroup 是無約束的,這意味著一旦上層程式需要 CPUShares,系統將優先考慮該程式。是不是感覺有點繞?所以我們最好在系統上對 Cgroup 的佈局進行視覺化,以避免混淆,這一點非常重要。

從上面的截圖中可以看到,所有的  cat 程式幾乎都接收到了相同數量的 CPU 時間。這是因為預設情況下 Cgroup 在  cpu.shares 檔案中的賦值是 1024。如前所述,這個份額是由父級與其他 Cgroup 的關係決定的。在本例中,我沒有調整任何父級的權重。因此,如果所有父級 Cgroup 同時需要資源的話,它們將以預設的 1024 CPUShares 的權重進行分配。

回過頭來,我在這裡建立了帶有預設值的 Cgroup,每個組的預設權重為 1024。如果要更改這個值,只需更改  cpu.shares 檔案即可:

# echo 2048 > user1/cpu.shares
# echo 768 > user2/cpu.shares
# echo 512 > user3/cpu.shares

現在,權重計算會變得更復雜。但因為我還沒有將任何程式新增到 Cgroup 中,它還處於未啟用狀態。如果要將程式新增到 Cgroup 中,將所需的 PID 新增到  tasks 檔案中就可以:

# echo 2023 > user1/tasks

同樣,可以在  top 中看到結果:


如圖所示,新 Cgroup 中的程式大致接收到了一半的 CPU 時間。這是因為按照之前的等式,可以計算出:

我們繼續將其他兩個程式新增到各自的 Cgroup 中並觀察結果:

# echo 2024 > user2/tasks
# echo 2025 > user3/tasks

可以看到權重已經生效, user1 佔用了大約 61% 的 CPU 時間。剩餘的時間分配給了  user2 和  user3

不過,我們的示例也存在幾個問題:

  1. 這些設定都是手動建立的,如果放入 Cgroup 中的程式的 PID 發生改變,會怎麼樣?

  2. 自定義的檔案和資料夾在重啟後不會儲存,怎麼辦?

  3. 大部分工作都需要手動完成,有哪些工具可用?

我知道你很急,但是你先別急,systemd 為我們提供了很好的解決方案。我們在下一篇文章中會涉及。

總結

現在我們已經知道如何手動管理 Cgroup 了,因此後面大家能夠更好地體會 Cgroup 和 systemd 協同使用的價值。

我將在本系列的第四篇,也就是完結篇中,深入探討這個想法。


來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70035809/viewspace-3001880/,如需轉載,請註明出處,否則將追究法律責任。

相關文章