Linux 核心中的 cpuset cgroup 繼承語義“壞了”什麼?
引用2013 年 systemd 新控制組界面的公告(添加了重點):
請注意,目前作為單元屬性公開的 cgroup 屬性的數量是有限的。這將在稍後擴展,因為它們的核心介面已被清理。例如**,由於核心邏輯的繼承語義被破壞,cpuset 或 freezer 目前根本沒有公開。**此外,不支持在執行時將單元遷移到不同的切片(即更改執行單元的 Slice= 屬性),因為核心目前缺少原子 cgroup 子樹移動。
那麼,核心邏輯的繼承語義有什麼問題
cpuset
(以及這種問題如何不適用於其他 cgroup 控制器,例如cpu
)?RedHat 網站上有一篇文章給出了一個未經驗證的解決方案,說明如何在 RHEL 7 中使用 cgroup cpusets,儘管它們缺乏作為易於管理的 systemd 單元屬性的支持……但這甚至是個好主意嗎?上面加粗的引文是有關的。
換句話說,使用此處引用的 cgroup v1 cpuset 可能會遇到哪些“陷阱”(陷阱)?
我正在為此開始賞金。
回答此問題的可能資訊來源(無特殊順序)包括:
- cgroup v1 文件;
- 核心原始碼;
- 測試結果;
- 現實世界的經驗。
上面引用中粗體線的一個可能含義是,當一個新程序被派生時,它不會與它的父程序保持在同一個 cpuset cgroup 中,或者它在同一個 cgroup 中但處於某種“未強制”狀態因此它實際上可能執行在與 cgroup 允許的不同的 CPU 上。但是,**這純粹是我的猜測,**我需要一個明確的答案。
此處的核心錯誤跟踪器中記錄了至少一個與 cpusets 相關的明確且未解決的問題:
錯誤 42789 - cpuset cgroup:當一個 CPU 下線時,它會從所有 cgroup 的 cpuset.cpus 中刪除,但當它上線時,它只會恢復到根 cpuset.cpus
從票證中引用一條評論(我將超連結添加到實際送出,並刪除 IBM 電子郵件地址以防垃圾郵件機器人):
這是由 Prashanth Nageshappa 獨立報告的……並在送出8f2f748b0656257153bcf0941df8d6060acc5ca6中修復,但隨後由 Linus 恢復為送出4293f20c19f44ca66e5ac836b411d25e14b9f185。根據他的承諾,該修復導致其他地方出現倒退。
修復送出(後來被恢復)很好地描述了這個問題:
目前,在 CPU hotplug 期間,cpuset 回調會修改 cpuset 以反映系統的狀態,並且這種處理是不對稱的。也就是說,在 CPU 離線時,該 CPU 將從所有 cpuset 中刪除。但是,當它重新聯機時,它只被放回根 cpuset。
這會在掛起/恢復期間產生重大問題。在掛起期間,我們將所有非引導 CPU 離線,而在恢復期間,我們將它們聯機。這意味著,在恢復之後,所有 cpuset(根 cpuset 除外)將被限制為僅一個 CPU(引導 cpu)。但是掛起/恢復的全部目的是將系統恢復到盡可能接近掛起之前的狀態。
描述了相同的非對稱熱插拔問題,並進一步了解它與繼承的關係,在:
錯誤 188101 - cgroup 的 cpuset 中的程序調度無法正常工作。
引用那張票:
當容器的 cpuset(docker/lxc 都使用底層 cgroup)變為空時(由於 hotplug/hotunplug),那麼在該容器中執行的程序可以在其最近的非空祖先的 cpuset 中的任何 cpu 上調度。
但是,當正在執行的容器(docker/lxc)的 cpuset 通過更新正在執行的容器的 cpuset(通過使用 echo 方法)從空狀態(將 cpu 添加到空 cpuset)變為非空時,在該容器中執行的程序仍然使用與其最近的非空祖先相同的cpuset。
雖然 cpuset 可能存在其他問題,但以上內容足以理解和理解 systemd 沒有公開或利用 cpuset “由於核心邏輯的繼承語義被破壞”的聲明。
從這兩個錯誤報告中,不僅 CPU 不會在恢復後重新添加回 cpuset,而且即使(手動)添加它們,該 cgroup 中的程序仍將在可能被 cpuset 不允許的 CPU 上執行。
我發現來自 Lennart Poettering 的一條消息直接證實了這一點(添加了粗體字):
2016 年 8 月 3 日星期三 16:56 +0200,Lennart Poettering 寫道:
2016 年 8 月 3 日星期三 14:46,Werner Fink 博士(suse.de 的 werner)寫道:
> > v228 的問題(我猜這也是來自目前 git 日誌的後來的 AFAICS)重複 CPU 熱插拔事件(離線/線上)。根本原因是cpuset.cpus 沒有被machined 恢復。請注意 libvirt 不能這樣做,因為它是不允許這樣做的。 > > >
這是核心 cpuset 介面的一個限制,也是**我們現在根本不在 systemd 中公開 cpuset 的原因之一。**值得慶幸的是,有一個 cpusets 的替代方案,它是通過 systemd 中的 CPUAffinity= 公開的 CPU 親和性控制項,它的作用大致相同,但語義較少。
我們想直接在 systemd 中支持 cpuset,但只要核心介面像它們一樣無聊,我們就不會這樣做。例如,當系統經歷掛起/恢復週期時,cpuset 目前被完全清除。
我對 cgroups 的了解還不夠,無法給出明確的答案(而且我當然沒有使用 2013 年的 cgroups 的經驗!)但是在香草 Ubuntu 16.04 cgroups v1 上似乎可以一起行動:
我設計了一個小測試,強制分叉為一個不同的使用者,使用一個
sudo /bin/bash
分離出來的孩子&
——這個-H
標誌是額外的偏執狂,強制sudo
在 root 的家庭環境中執行。cat <(whoami) /proc/self/cgroup >me.cgroup && \ sudo -H /bin/bash -c 'cat <(whoami) /proc/self/cgroup >you.cgroup' & \ sleep 2 && diff me.cgroup you.cgroup
這產生:
1c1 < admlocal --- > root
作為參考,這是我係統上 cgroup 掛載的結構:
$ mount | grep group tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755) cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd) cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset) cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory) cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer) cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio) cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct) cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids) cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb) cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices) cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event) lxcfs on /var/lib/lxcfs type fuse.lxcfs (rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other) $