Linux 控制群組第二版

最後更新: 2022-10-15 15:47:14 +0800 +0800
tags: Cgroups | Kernel | Linux
原文以英文撰寫。您正在閱讀AI翻譯版本。

控制群組(cgroup)會記帳並控制 Linux 工作的集合。cgroup 不是程序樹節點:工作在 fork 時繼承父項的 cgroup,但管理器之後可以遷移它。因此,cgroup 提供服務管理器與容器背後的資源邊界,而命名空間提供全域資源的檢視。

本文描述 cgroup 第二版(cgroup v2)。其文件化介面是 cgroup2 檔案系統;檔案與支援的控制器取決於執行中的核心設定與可用硬體。

統一階層與成員資格 #

Cgroup v2 具有一個統一階層。每個工作都恰好屬於該階層中的一個 cgroup,包括未命名的根 cgroup。子 cgroup 會繼承祖先允許的限制與控制器設定,因此子項不能取得其父項未委派的 CPU、記憶體或裝置。

階層由 cgroup2 掛載表示,慣例位置為 /sys/fs/cgroup:

sh
findmnt -t cgroup2
cat /proc/self/cgroup
ps -o pid,cgroup,comm -p $$

每個目錄都是 cgroup。建立目錄會建立子 cgroup,將 PID 寫入其 cgroup.procs 會遷移程序的執行緒群組:

sh
sudo mkdir /sys/fs/cgroup/build
printf '%s\n' "$$" | sudo tee /sys/fs/cgroup/build/cgroup.procs

請使用服務管理器,而不要手動移動其自身程序。例如,systemd 為 slice、scope 與服務建立並管理 cgroup;手動遷移可能違反管理器的記帳與生命週期假設。

網域與執行緒 cgroup #

一般階層由網域 cgroup 組成,其控制器將程序視為單位套用。內部無程序規則防止非根網域 cgroup 同時包含程序,並將網域控制器分發給子項。將工作移至葉節點,使用空的中間節點在子 cgroup 之間配置控制器:

w├└o──r──klctooeamsdptsis/l/er/###eccnooannbttlaaeiisnnsscoctnoetmsrptoillplererorcspersfosoceresscsheisldren;noprocesses

根 cgroup 不受此規則限制。透過 cgroup.type 設定的執行緒子樹,允許使用 cgroup.threads 放置個別執行緒。它適用於執行緒感知控制器,並具有額外結構限制;它不會將每個控制器變成每執行緒限制。混合執行緒與網域子樹前,請檢查 cgroup.type 與核心文件。

控制器與啟用 #

控制器是實作資源原則的核心程式碼。可用性與啟用是不同概念:

  • cgroup.controllers 列出父項已提供給 cgroup 子項的控制器。
  • cgroup.subtree_control 列出已啟用以控制那些子項的控制器。寫入 +name 或 -name 來變更它。
  • 控制器介面檔案只會在控制器、設定與裝置上下文使其適用的位置出現。

對新的子樹,先在父項啟用控制器,再設定子 cgroup。非根網域 cgroup 為其子項啟用網域控制器時,不得包含程序。

sh
cd /sys/fs/cgroup
cat cgroup.controllers
sudo sh -c 'printf "+cpu +memory +pids\n" > cgroup.subtree_control'
sudo mkdir build
sudo sh -c 'printf "50000 100000\n" > build/cpu.max'
sudo sh -c 'printf "2G\n" > build/memory.max'
sudo sh -c 'printf "512\n" > build/pids.max'

範例中的 cpu.max 允許每 100,000 微秒週期使用 50,000 微秒 CPU 時間。它會限制彙總 CPU 頻寬,不會保留專用 CPU。有效控制器集合仍受每個祖先限制。

控制器介面 #

根部的控制器名稱識別特定核心暴露的內容。目前 v2 文件涵蓋下列資源控制器家族:

控制器代表檔案原則
CPUcpu.weight、cpu.max、cpu.stat比例共用、頻寬上限與節流統計。
記憶體memory.current、memory.min、memory.low、memory.high、memory.max、memory.swap.max、memory.events記帳、保護、節流/回收壓力、硬限制、交換限制與 OOM 事件。
I/Oio.weight、io.max、io.stat、io.pressure比例與每裝置頻寬/IOPS 控制及統計。
Cpusetcpuset.cpus、cpuset.cpus.effective、cpuset.mems、cpuset.mems.effective要求與有效的 CPU 及 NUMA 節點放置。
PIDspids.current、pids.max、pids.events目前程序數、硬性程序限制與觸及限制事件。
HugeTLBhugetlb.<size>.current、hugetlb.<size>.max、hugetlb.<size>.events每種巨大頁面大小的使用量與限制。
RDMArdma.max、rdma.current、rdma.events每個 RDMA 裝置 HCA 物件與控制代碼的限制、使用量與失敗。
Miscmisc.current、misc.max、misc.events已註冊純量資源的限制。

memory.high 是回收與節流邊界,而 memory.max 是硬限制;當回收無法進展時,可能導致 cgroup 本地 OOM 處理。memory.oom.group 可以要求以群組為導向終止工作。變更限制前,請讀取 memory.events、memory.stat 與壓力停滯資訊;符合穩態 RSS 的限制,在頁面錯誤、fork 或快取成長期間仍可能失敗。

cpuset.cpus 與 cpuset.mems 表達受父項限制的要求。其 *.effective 對應項顯示實際授予的 CPU 與 NUMA 節點,包括熱插拔效果。CPU 親和性與 cpuset 會取交集,因此任一機制都能縮小工作執行的位置。

常見 Cgroup 檔案 #

除控制器檔案外,cgroup v2 提供階層範圍的檔案:

  • cgroup.procs 列出 cgroup 中的執行緒群組 ID,並接受 PID 遷移。
  • cgroup.threads 列出執行緒子樹中的執行緒,並接受執行緒 ID。
  • cgroup.events 回報 cgroup 或其後代是否已填入等狀態;poll 或 inotify 可以觀察變更。
  • cgroup.freeze 停止並恢復非根子樹中的執行,而 cgroup.kill 終止非根子樹中的所有程序。
  • cgroup.max.depth 與 cgroup.max.descendants 限制階層成長。
  • cgroup.stat、cgroup.type 與 cgroup.controllers 暴露階層及控制器狀態。

檔案寫入是作業,不是設定交易。管理器必須處理 EBUSY、權限失敗、熱插拔變更、並行遷移與部分設定。介面允許無界值時,限制可以寫成 max。

委派、命名空間與容器 #

委派讓下屬管理器控制子樹,而不授予其祖先控制權。委派者建立空 cgroup、在其父項啟用必要控制器、將擁有權或存取權授予子樹,並允許受委派者建立與管理後代。受委派者必須只在該邊界以下運作,因為祖先設定決定其可用資源。

systemd 的 Delegate=yes 是建立此類邊界的常見方式。容器執行階段接著組合數個機制:

  1. 建立或選取 cgroup,並套用主機資源原則;
  2. 建立使用者、掛載、PID、網路及其他命名空間;
  3. 安排私有掛載檢視,並在 PID 命名空間存在後掛載 /proc;
  4. 執行工作負載,並保留主機側的生命週期作業控制代碼。

Cgroup 命名空間會變更程序看到的 cgroup 路徑檢視:/proc/PID/cgroup 與 cgroup 檔案系統路徑會相對於該命名空間為根。它不會建立獨立控制器階層、放寬祖先限制或隔離資源記帳。主機側管理器仍保留權威階層。

核心表示 #

使用者可見的樹由核心中的 cgroup 物件支援。task_struct 指向 css_set;css_set 將作用中控制器的 cgroup_subsys_state(CSS)參照分組。控制器會將其狀態嵌入 CSS 或與 CSS 關聯,並在其記帳與強制路徑中使用該關聯。工作可以共用 css_set,避免為每個工作重複相同的控制器狀態組合。

這些實作細節說明遷移必須一致更新控制器成員資格,但它們不是穩定的使用者空間 ABI。特定核心版本請參閱 kernel/cgroup/cgroup.c 與 include/linux/cgroup-defs.h。

與 Cgroup 第一版比較 #

第一版允許多個獨立階層,並將控制器附加至不同階層。因此,一個工作可以對不同控制器具有不同成員資格,讓應用程式的資源邊界難以推理。Cgroup v2 使用單一階層、共用委派規則與一致的控制器介面。系統可以在遷移期間掛載 v1 與 v2,但控制器不能同時繫結至兩個版本。

權威且特定版本的參考資料是 cgroup v2 核心文件。請檢查目標核心的 cgroup.controllers 與該文件,而不要假設控制器或介面檔案存在。

評論

在 GitHub 上閱讀或評論(發表評論需要登入)