Managing a single process resources running on top of an operating system is not a trivial task. While solutions like Docker or Virtual Machines could completely isolate your process, I was recently looking for a simpler and more straightforward solution at operating system level.
Then I discovered cgroups which is a kernel tool to limit resource usage per user-defined groups. The resources I was mostly interested in are CPU and RAM, but there is also an option to limit the IO usage of a process. To run a new process with limited resources you basically have to remember two things:
- Define the cgroup resource limits
- Run your process within the croup like:
sudo cgexec -g cpu:root -g memory:root COMMAND
In my ubuntu server I used the stress tool to generate some load in the machine so I could actually check if the resource limits being applied.
Here are the steps I followed for the cgroups installation:
Install cgoup-bin
sudo apt-get install cgroup-bin
Create a custom group for your process
mount {
cpu = /cgroup/cpu;
cpuacct = /cgroup/cpu;
memory = /cgroup/memory;
}
group dataparser {
# Set the cpu and memory limits for this group
cpu {
cpu.shares = 500;
}
memory {
memory.limit_in_bytes = 40G;
}
}
Setting cgroup limits
sudo mkdir /cgroup/cpu/dataparser
sudo mkdir /cgroup/memory/dataparser
#Limit CPU usage to 50%
echo 500 > /cgroup/cpu/dataparser/cpu.shares
# Limit RAM to 40G
echo 40000000000 > /cgroup/memory/dataparser/memory.limit_in_bytes
Mount the cgroups
sudo mount -t cgroup -o cpu,cpuacct cpu /cgroup/cpu/
sudo mount -t cgroup -o memory memory /cgroup/memory/
Create the cgroup with the resource limits
sudo cgcreate -a dataparser:dataparser -t dataparser:dataparser -g cpu:dataparser
Test limits using stress tool
At that point the CPU and RAM usage of you process should never exceed the limits you defined! I found stress tool really useful in this part.
sudo cgexec -g cpu:dataparser -g memory:dataparser stress --cpu 20 --vm 50 --vm-bytes 10G
Extra commands
list mounted cgroups
lscgroup
deleted all cgroups (use with caution)
sudo cgclear
load configuration file
sudo cgconfigparser -l /etc/cgconfig.conf
Of course you could define which users can run processes within each cgroup and also which users can modify resource limits. These options are mostly useful in a multiuser environment with multiple croups defining different resource limits. You can find more information here. I also have to mention here that Docker is using the same trick with croups inside containers to manage the recourses.