还有类似的问题:Cgroups,限制每个用户的内存但该解决方案在“现代”系统中不起作用,因为 cgroups 层次结构由 systemd 管理。
直接的解决方案 — 模板化 user-UID.slice — 不起作用,因为它不受支持,请参阅https://github.com/systemd/systemd/issues/2556。
有没有什么方法可以达到预期的效果——根据每个用户管理 CPU 和/或内存资源?
更新型多巴胺:为了历史,我将保留我的解决方案,但systemctl set-property
应该在登录时使用来调用,pam_exec
请参阅https://github.com/hashbang/shell-etc/pull/183. 在这种方法中,用户登录和设置限制之间没有时间窗口。
我的解决方案。org.freedesktop.login1.Manage
对象接口/org/freedesktop/login1
发出UserNew(u uid, o object_path)
信号。我编写了一个简单的守护进程,它监听信号,并且每次发出信号时都会CPUAccounting=true
为刚登录的用户的切片设置。
答案1
从 systemd v239 开始,你可以使用插件 https://github.com/systemd/systemd/commit/5396624506e155c4bc10c0ee65b939600860ab67
# mkdir -p /etc/systemd/system/user-.slice.d
# cat > /etc/systemd/system/user-.slice.d/50-memory.conf << EOF
[Slice]
MemoryMax=1G
EOF
# systemctl daemon-reload
答案2
更新型多巴胺:为了历史,我将保留我的解决方案,但systemctl set-property
应该在登录时使用来调用,pam_exec
请参阅https://github.com/hashbang/shell-etc/pull/183. 在这种方法中,用户登录和设置限制之间没有时间窗口。
旧解决方案
这是一个非常简单的脚本,可以完成这项工作
#!/bin/bash
STATE=1 # 1 -- waiting for signal; 2 -- reading UID
dbus-monitor --system "interface=org.freedesktop.login1.Manager,member=UserNew" |
while read line
do
case $STATE in
1) [[ $line =~ member=UserNew ]] && STATE=2 ;;
2) read dbus_type ID <<< $line
systemctl set-property user-$ID.slice CPUAccounting=true
STATE=1
;;
esac
done
它可以轻松扩展以支持每个用户的内存限制。
在具有 2 个 CPU 和 2 个用户的虚拟机上进行了测试。第一个用户运行dd if=/dev/zero of=/dev/null | dd if=/dev/zero of=/dev/null
命令,第二个用户只运行 的一个实例dd
。如果不运行此脚本, 的每个实例dd
都会使用大约 70% 的 CPU。
然后我启动了脚本,重新登录用户,并dd
再次启动命令。这一次,dd
第一个用户的两个进程各自只占用了 50% 的 CPU,而第二个用户的进程占用了 100% 的 CPU。此外,还systemd-cgtop
显示,/user.slice/user-UID1.slice
和/user.slice/user-UID2.slice
各自占用了 100% 的 CPU 时间,但第一个切片有 6 个任务,而第二个切片只有 5 个任务。
当我终止dd
第二个用户的任务时,第一个用户开始消耗 200% 的 CPU 时间。因此,我们有公平的资源分配,而没有“每个用户只能使用一个核心”这样的人为限制。
答案3
您提到的问题仍然未解决,但这对我来说有用。
sudo systemctl edit --force user-1234.slice
然后输入并保存:
[Slice]
CPUQuota=10%
我不确定它为什么有效。
答案4
在 Ubuntu 上,我需要将TasksMax
单个用户(即运行我组所有测试的 CI 服务用户 (UID 2000))的默认限制从 10813 增加到更高的值。我使用 检查了旧限制sudo systemctl status user-2000.slice
,然后通过键入并输入以下内容设置了新限制sudo systemctl edit --force user-2000.slice
:
[Slice]
TasksMax=50000
这将更新限制并创建/etc/systemd/system/user-2000.slice.d/override.conf
包含上述设置的文件。我将该文件添加到我的 Ansible playbook 中,现在它已部署到我们所有的机器上,因此即使我们重建服务器,限制仍保持不变。