我有一个 cgroup 设置,主要用于限制 rsync 和 Firefox 的内存使用。这是一个手动设置(不涉及 systemd),每次启动后我都会从 Makefile 运行它(是的,我知道这不是很好,但是 systemd 学习起来很麻烦)。
今天,当我从 ubuntu 21.04 升级到 22.04 时,意外后果定律确保我的 cgroup 设置不再起作用,可能是因为 cgroup V2 现在是标准。
在我看来,/sys/fs/cgroups 中的文件层次结构已经发生了变化。例如,我以前有用户 reik
/sys/fs/cgroup/内存/自定义/reik-2048M
我使用 Makefile 代码片段创建了该脚本,并生成了以下脚本
MEM=2048M
sudo cgcreate -a reik -t reik -g memory:/custom/reik-$(MEM)
sudo cgset -r memory.limit_in_bytes=$(MEM) custom/reik-$(MEM)
sudo cgset -r memory.memsw.limit_in_bytes=$(MEM) custom/reik-$(MEM)
然后我可以运行如下程序
%gexec --sticky -g 内存:custom/reik-2048M 某个程序
使用 cgroup v2 时,memory.blah 变量名称已经改变,我认为我已经修复了这个问题,如下所示
sudo cgcreate -a reik -t reik -g memory:/custom/reik-2048M
sudo cgset -r memory.max=2048M custom/reik-2048M
sudo cgset -r memory.swap.max=2048M custom/reik-2048M
但是现在,如果我尝试运行任何程序(比如 ls),就会出现错误,如下所示
% cgexec --sticky -g memory:custom/reik-2048M ls
cgroup change of group failed
有一点似乎不同,那就是文件层次结构中不再包含 /memory/ 组件,也就是说,创建的路径只是
/sys/fs/cgroup/custom/reik-2048M
我只能做到这些了。我正在寻找我在这里做错的事情的想法。我还查找了有关如何将 cgroup v1 命令转换为 cgroup v2 的文档,但没有找到任何非常具体的内容。
答案1
总结:
systemd-run --user -G -P -d -p MemoryMax=2G -p MemorySwapMax=2G ls
这将使用指定的设置和命令动态创建一个 .service。(对于 .service 单元,相同的设置将进入 [Service] 部分。)这会--user
使其在您自己的服务管理器下运行,而不是在系统范围的服务管理器下运行。
可以通过systemd-run (或在真实的 .service 单元中) 创建~/.config/systemd/user/foo.slice
和使用预定义的 cgroup :--slice
Slice=
[Slice]
MemoryMax=2G
MemorySwapMax=2G
# systemd-run --user --collect --slice=foo.slice --pty --shell
(关于 systemd 的切片命名的注意事项:破折号是层次分隔符,即foo-bar.slice
是 的子项foo.slice
。)
在我看来,/sys/fs/cgroups 中的文件层次结构已经发生了变化。[…] 有一点似乎不同,那就是文件层次结构中不再包含 /memory/ 组件,也就是说,创建的路径只是
是的,这在很大程度上解释了为什么它是 cgroups“v2”。新的 cgroups 系统不再有单独的每个控制器树 - 所有内容都只有一个树,子树通过其cgroup.controller
文件启用特定的控制器(cgcreate 自动执行此操作)。
但是,在我的测试中,CGROUP_LOGLEVEL=debug
错误消息表明内核不允许将 PID 移入新的 cgroup。我不确定原因,但最有可能的原因是,您没有遵守 cgroup.c 中的“应被授权迁移到共同祖先”规则 - 在这种情况下,唯一的共同祖先是根/
cgroup,而您没有权限。
(systemd-run 并不直接执行进程,而是要求进程systemd --user
执行它,因此源 cgroup 和目标 cgroup 都属于共同的祖先,[...]/[email protected]
是归您的 UID 所拥有,因此通过了迁移检查。)
这导致了另一个值得一提的区别——在 v2 模型中,cgroup 可以有任务或者但不能同时存在两个子组,所以你不能实际上将任何进程移入祖先 cgroup;上一段使用“授权迁移”严格是指对共同祖先具有写权限cgroup.procs
。