Preventing Service Cascades with systemd and cgroup v2 Resource Limits
Stop a single leaking service from crashing your entire Linux host. Learn how to use cgroup v2 and systemd to implement hard memory and CPU limits that isolate failures.
21 Jul 2026, 05:19 UTC

The 'Noisy Neighbor' Problem in Linux Services
A single memory leak in a background worker or a CPU-bound loop in a web server can trigger a system-wide failure. When a process consumes all available RAM, the Linux Out-of-Memory (OOM) killer may target critical system processes or unrelated services, leading to a cascading failure where the entire host becomes unresponsive.
The solution is to move from reactive monitoring to proactive isolation. By using cgroup v2 (Control Groups version 2) integrated with systemd, you can define hard boundaries for every service. This ensures that if a service misbehaves, it is throttled or killed in isolation, leaving the rest of the system untouched.
The Shift to the Unified Hierarchy
Unlike cgroup v1, which used separate hierarchies for CPU, memory, and I/O, cgroup v2 uses a unified hierarchy. This means a process belongs to exactly one group, and all resource controllers (memory, CPU, I/O) are applied to that single group. This eliminates the complexity of managing multiple directory trees in /sys/fs/cgroup.
Modern Linux distributions (such as Ubuntu 22.04+, Fedora, and RHEL 9) enable cgroup v2 by default. systemd leverages this by automatically creating a cgroup for every unit it manages, allowing you to set limits directly in the .service file without manually touching the kernel filesystem.
Implementing Resource Caps in systemd
To constrain a service, you add resource directives to the [Service] section of your unit file. The most critical directives are:
MemoryMax=: The hard limit. If the service hits this, the kernel invokes the OOM killer for processes within that cgroup.MemoryHigh=: A "soft" limit. The kernel will aggressively throttle the process and attempt to reclaim memory before hitting the hard limit.CPUQuota=: Limits the percentage of CPU time the service can use (e.g.,50%means half of one CPU core).
Worked Example: Isolating a Memory-Hungry Web App
Imagine a Python-based API that occasionally spikes in memory usage. To prevent it from crashing the host, create or edit the service file (e.g., /etc/systemd/system/api-service.service):
[Unit]
Description=Memory-Limited API Service
[Service]
ExecStart=/usr/bin/python3 /opt/api/app.py
Restart=always
# Hard limit: Kill the service if it exceeds 512MB
MemoryMax=512M
# Soft limit: Start throttling/reclaiming at 400MB
MemoryHigh=400M
# Limit to 1.5 CPU cores
CPUQuota=150%
[Install]
WantedBy=multi-user.target
Deployment Steps:
- Reload the daemon:
sudo systemctl daemon-reload(Run as root/sudo). - Restart the service:
sudo systemctl restart api-service. - Verify the limit is active by checking the cgroup filesystem:
cat /sys/fs/cgroup/system.slice/api-service.service/memory.max.
Trade-offs and Limitations
While cgroup v2 provides stability, it introduces specific operational risks:
- Silent Failures: If
MemoryMaxis too tight, your application may crash with an OOM error without a traditional stack trace in the app logs. You must checkdmesgorjournalctl -xeto see the kernel's OOM kill event. - I/O Complexity: Block I/O limits (like
IOReadBandwidthMax) require the device path (e.g.,/dev/sda). Applying a generic limit without a device path often results in the setting being ignored. - Container Conflicts: If you run Docker or Podman on the same host, ensure the runtime is configured for cgroup v2. Mixing v1 and v2 (hybrid mode) can lead to unpredictable resource enforcement.
Verification and Diagnostics
To confirm your system is actually using cgroup v2, run this command on the host:
mount | grep cgroup2
If you see type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate), the unified hierarchy is active.
To monitor real-time usage against your limits, use systemd-cgtop. This tool provides a live view of which service groups are consuming the most resources, allowing you to tune your MemoryHigh and CPUQuota values based on actual production telemetry.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.