Cgroups

如何使用 cgroups 將除白名單之外的所有程序限制為單個 CPU?

  • September 14, 2018

Red Hat有一個cgroups 指南,它可能有點幫助(但沒有回答這個問題)。

我知道如何在啟動該程序的命令期間將特定程序限制為特定 CPU,方法是:

首先,將以下*放入/etc/cgconfig.conf

mount {
 cpuset =  /cgroup/cpuset;
 cpu =     /cgroup/cpu;
 cpuacct = /cgroup/cpuacct;
 memory =  /cgroup/memory;
 devices = /cgroup/devices;
 freezer = /cgroup/freezer;
 net_cls = /cgroup/net_cls;
 blkio =   /cgroup/blkio;
}

group cpu0only {
 cpuset {
   cpuset.cpus = 0;
   cpuset.mems = 0;
 }
}

然後啟動一個程序並使用以下命令將其專門分配給該 cgroup:

cgexec -g cpuset:cpu0only myprocessname

我可以通過(我認為這是正確的)將以下內容自動限制特定程序名稱的所有實例/etc/cgrules.conf

# user:process  controller  destination
*:myprocessname cpuset      cpu0only

我的問題是:我該如何做相反的事情?

換句話說,我如何將除一組特定的白名單程序*及其子程序之外的所有*程序分配給受限制的 cgroup?**


根據我所研究但尚未測試的內容,我相信部分**解決方案是:

添加一個“不受限制”的 cgroup:

group anycpu {
 cpuset {
   cpuset.cpus = 0-31;
   cpuset.mems = 0;  # Not sure about this param but it seems to be required
 }
}

將我的程序顯式分配給不受限制的組,並將其他所有內容分配給受限制的組:

# user:process  controller  destination
*:myprocessname cpuset      anycpu
*               cpuset      cpu0only

然而,對此的警告似乎是(從閱讀文件,而不是從測試,所以一粒鹽)的孩子myprocessname將被重新分配到受限制的cpu0onlycgroup。

一種可能的替代方法是創建一個使用者來執行myprocessname,並使該使用者的所有程序不受限制,而其他一切都受到限制。但是,在我的實際案例中,該程序需要由 root 執行,並且還有其他程序也必須由 root 執行,應該受到限制。

如何使用 cgroups 完成此任務?


如果 cgroups 無法做到這一點(我現在懷疑是這種情況),我對部分解決方案的想法是否正確,它們會像我想的那樣工作嗎?

免責聲明:這可能不是一個最小的程式碼範例;我不了解所有*部分,所以我不知道哪些是不必要的。

更新:請注意,以下答案適用於 RHEL 6。在 RHEL 7 中,大多數 cgroup 由 systemd 管理,並且不推薦使用 libcgroup。


自從發布這個問題以來,我已經研究了上面連結到的整個指南,以及cgroups.txt文件和cpusets.txt的大部分內容。我現在對 cgroups 的了解比我預期的要多,所以我將在這裡回答我自己的問題。

您可以採取多種方法。我們公司在 Red Hat 的聯繫人(一名技術架構師)建議不要對所有流程進行全面限制,而是採用更具聲明性的方法——僅限制我們特別希望限制的流程。根據他關於該主題的陳述,其原因是系統呼叫可能依賴於使用者空間程式碼(例如 LVM 程序),如果受到限制,可能會減慢系統速度——與預期效果相反。所以我最終限制了幾個特別命名的程序,而把其他一切都放在一邊。

此外,我想提一下我在發布問題時缺少的一些cgroup 基本數據。


Cgroups依賴於libcgroup安裝。 但是,這是一組用於自動處理 cgroup 配置和程序分配給 cgroup 的工具,非常有用。

我發現 libcgroup 工具也可能會產生誤導,因為 libcgroup 包是建立在它自己的一組關於您使用 cgroups 的抽象和假設之上的,這與 cgroups 的實際核心級實現略有不同。(我可以舉一些例子,但這需要一些工作;如果您有興趣,請發表評論。)

因此,在使用 libcgroup 工具(例如/etc/cgconfig.conf, /etc/cgrules.conf, cgexec, cgcreate,cgclassify等)之前,我強烈建議您非常熟悉/cgroup虛擬文件系統本身,並手動創建 cgroups、cgroup 層次結構(包括附加多個子系統的層次結構,libcgroup 偷偷地和洩漏地抽像出來) away),通過執行將程序重新分配給不同的 cgroup echo $the_pid > /cgroup/some_cgroup_hierarchy/a_cgroup_within_that_hierarchy/tasks,以及在後台執行的其他看似神奇的任務libcgroup


我缺少的另一個基本概念是,如果/cgroup虛擬文件系統完全安裝在您的系統上(或者更準確地說,如果安裝了任何 cgroup 子系統,即“控制器”),那麼整個系統上的每個程序**都在c組。 沒有“某些程序在 cgroup 中,而有些不在”這樣的事情。

對於給定的層次結構,有一個所謂的cgroup,它擁有所連接子系統的所有系統資源。例如,附加了 cpuset 和 blkio 子系統的 cgroup 層次結構將具有一個根 cgroup,該 cgroup 將擁有系統上的所有cpus 和系統上的所有 blkio,並且可以與**子cgroup共享其中一些資源。您不能限制根 cgroup,因為它擁有您系統的所有資源,因此限制它甚至沒有意義。


我還缺少一些關於 libcgroup 的其他簡單數據:

如果使用/etc/cgconfig.conf,則應確保將chkconfig --list cgconfig顯示cgconfig設置為在系統啟動時執行。

如果更改/etc/cgconfig.conf,則需要執行service cgconfig restart以載入更改。(在測試時,停止服務或執行cgclear的問題很常見。對於調試,我建議,例如,lsof /cgroup/cpuset如果cpuset是您正在使用的 cgroup 層次結構的名稱。)

如果要使用/etc/cgrules.conf,則需要確保“cgroup 規則引擎守護程序”( cgrulesengd) 正在執行:service cgred start並且chkconfig cgred on. (並且您應該注意關於此服務的可能但不太可能出現的爭用情況,如頁面底部第 2.8.1 節中的紅帽資源管理指南中所述。)

如果您想手動玩轉並使用虛擬文件系統(我建議首次使用)設置您的 cgroup,您可以這樣做,然後使用其各種選項創建一個cgconfig.conf文件來鏡像您的設置。cgsnapshot


最後,當我寫以下內容時,我缺少的關鍵資訊:

但是,對此的警告似乎是…… myprocessname 的孩子將被重新分配給受限制的 cpu0only cgroup。

我是對的,但有一個我不知道的選項。

cgexec是啟動程序/執行命令並將其分配給 cgroup 的命令。

cgclassify是將已經執行的程序分配給 cgroup 的命令。

這兩者還將阻止cgred( cgrulesengd) 將指定程序重新分配給基於/etc/cgrules.conf.

兩者cgexec和都cgclassify支持該--sticky標誌,這可以防止cgred重新分配基於/etc/cgrules.conf.


所以,我寫的這個問題的答案(雖然不是我最終實施的設置,因為上面提到了我們的紅帽技術架構師的建議)是:

按照我的問題中的描述創建cpu0only和cgroup。anycpu(確保cgconfig設置為在啟動時執行。)

* cpuset cpu0only按照我的問題中的描述制定規則。(並確保cgred設置為在啟動時執行。)

啟動我想要不受限制的任何程序:cgexec -g cpuset:anycpu --sticky myprocessname.

這些程序將不受限制,它們的所有子程序也將不受限制。 系統上的所有其他內容都將被限制為 CPU 0(一旦您重新啟動,因為cgred除非它們更改其 EUID,否則不會將 cgrules 應用於已經執行的程序)。這不是完全可取的,但這是我最初要求的,可以使用 cgroups 完成。

引用自:https://unix.stackexchange.com/questions/247209