LinuxXXXVII · Resource Managementsystemd resource controls
systemd resource controls - applying cgroups via units
What you'll learn
- Apply resource controls via systemd
- Use CPU, Memory, IO directives
- Configure slices for hierarchical limits
- Inspect resource usage per service
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09
systemd uses cgroups to manage resources for every service.
Directives in the [Service] and [Slice] sections set
limits. This lesson covers the production patterns.
Service-level directives
[Service]
# 2 CPUs
CPUQuota=200%
# hard limit
MemoryMax=4G
# soft limit; reclaim above
MemoryHigh=3G
# I/O weight (1-10000)
IOWeight=100
# max PIDs/threads
TasksMax=1024
Note where the comments sit. Each one is on a line of its own, above the directive it explains. That is not a style preference. It is the only form systemd accepts.
CPUQuota always takes a percentage
CPUQuota= takes a percentage value with a mandatory %
suffix, where 100% is one full core. There is no
bare-integer form:
# WRONG - "Invalid CPU quota '4', ignoring." The unit gets no quota.
CPUQuota=4
# RIGHT - 4 CPUs
CPUQuota=400%
A bare 4 is not read as “4 CPUs” and is not read as “4%”.
It is rejected outright, so the service runs unconstrained on
every core. Confirm the quota landed:
systemctl show my-service -p CPUQuotaPerSecUSec
# CPUQuota=400% -> CPUQuotaPerSecUSec=4s (4 CPU-seconds per second)
# no quota -> CPUQuotaPerSecUSec=infinity
Slice-level directives
Slices group services for hierarchical limits:
# /etc/systemd/system/production.slice
[Slice]
# 4 CPUs for all services in this slice
CPUQuota=400%
# 16 GB total for the slice
MemoryMax=16G
Place services in a slice:
# /etc/systemd/system/my-service.service
[Service]
Slice=production.slice
ExecStart=/usr/local/bin/my-service
Inspect
# Show resource usage per service
systemd-cgtop
# Detailed view of a service
systemctl status my-service
# cgroup filesystem view
ls /sys/fs/cgroup/system.slice/my-service.service/
cat /sys/fs/cgroup/system.slice/my-service.service/memory.current
cat /sys/fs/cgroup/system.slice/my-service.service/memory.events
Common production patterns
Web server with a budget
[Service]
CPUQuota=400%
MemoryMax=8G
MemoryHigh=6G
IOWeight=200
TasksMax=2048
Database with persistent memory
[Service]
# 8 CPUs
CPUQuota=800%
# hard limit; OOMs above this
MemoryMax=32G
# higher I/O priority
IOWeight=500
Background job with low priority
[Service]
# half a CPU
CPUQuota=50%
MemoryMax=2G
# lowest I/O priority
IOWeight=10
# lowest CPU scheduling priority
Nice=19
Hierarchical limits
Slices can be nested:
production.slice (4 CPUs, 16 GB)
├── web.slice (3 CPUs, 8 GB)
│ ├── nginx.service
│ └── app.service
└── db.slice (3 CPUs, 8 GB)
└── postgresql.service
Inner slices cannot exceed their parent’s limits. This gives hierarchical resource control.
Memory tuning
To reduce the chance of an OOM kill:
[Service]
# soft limit; reclaim and throttling start here
MemoryHigh=3G
# hard limit; crossing it means a cgroup OOM kill
MemoryMax=4G
# MemorySwapMax is deliberately NOT set: swap is the escape valve
MemoryHigh triggers reclaim rather than an OOM kill, so the
gap between the two values is your warning band. It is not a
guarantee of survival: a service whose working set genuinely
exceeds MemoryHigh is throttled hard enough to fail health
checks, and it is still killed if it reaches MemoryMax.
CPU tuning
For CPU-bound services:
[Service]
# 4 CPUs; the % suffix is mandatory
CPUQuota=400%
# relative weight if CPU is contended
CPUWeight=200
CPUQuota is a hard limit. CPUWeight is relative.
Knowledge check
Knowledge check · 5 questions
Q1. What is the difference between MemoryMax and MemoryHigh?
Q2. Inner slices can exceed parent slice limits.
Q3. Which of the following are valid systemd resource directives? Select all that apply.
Q4. A colleague writes `MemoryMax=4G # hard limit` in a unit file, reloads, and starts the service. The service later consumes 30 GB and the host OOMs. What happened?
Q5. You want to cap a batch service at four cores. Which directive does that?
Passing score: 75%. Answers are checked in this browser.