systemd, per-user cpu and/or memory limits
Solution 1:
UPD: I'll keep my solution for the sake of history, but systemctl set-property
should be called at login time, using pam_exec
, see https://github.com/hashbang/shell-etc/pull/183. In this approach, there is no time window between the user's login and setting of limits.
Old solution
Here is a very simple script which does the job
#!/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
It can be easily extended to support per-user memory limits.
Tested it on a VM with 2 CPUs and 2 users. The first user run dd if=/dev/zero of=/dev/null | dd if=/dev/zero of=/dev/null
command and the second one run only one instance of dd
. Without this script running, each instance of dd
used around 70% of CPU.
Then I started the script, relogged users, and starded dd
commands again. This time two dd
processes of the first user took only 50% of CPU each and the process of the second user took 100% of CPU. Also, systemd-cgtop
showed, that /user.slice/user-UID1.slice
and /user.slice/user-UID2.slice
take 100% of CPU time each, but the first slice has 6 tasks and the second one only 5 tasks.
When I kill dd
task of the second user, the first user starts consuming 200% of CPU time. So, we have fair resource allocation without artificial restrictions like "each user may use only one core".
Solution 2:
Starting with systemd v239, you can use drop-ins 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