systemd、每个用户的 CPU 和/或内存限制

int*_*lfx 9 user-management resource-management limits systemd

有类似的问题:Cgroups, limit memory per user,但该解决方案在“现代”系统中不起作用,其中 cgroups 层次结构由 systemd 管理。

简单的解决方案——模板 user-UID.slice——将不起作用,因为它不受支持,请参阅https://github.com/systemd/systemd/issues/2556

有没有办法达到预期的效果——基于每个用户管理 CPU 和/或内存资源?

UPD:为了历史起见,我将保留我的解决方案,但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为刚刚登录用户的切片。

int*_*lfx 6

UPD:为了历史记录,我将保留我的解决方案,但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
Run Code Online (Sandbox Code Playgroud)

它可以轻松扩展以支持每个用户的内存限制。

在具有 2 个 CPU 和 2 个用户的 VM 上进行了测试。第一个用户运行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 时间。因此,我们有公平的资源分配,没有“每个用户只能使用一个核心”之类的人为限制。


小智 5

从 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
Run Code Online (Sandbox Code Playgroud)