In my environment, I often run multiple services on the same host — databases, web apps, monitoring tools — and without proper limits, one misbehaving process can consume all available memory or disk IO, affecting everything else. That’s where systemd Slice comes in. It allows me to group services and apply resource constraints at the slice level, ensuring fair sharing and isolation. I’ve used this approach to protect critical systems from noisy neighbors, especially in mixed workloads on Proxmox or bare metal servers.
Why Use systemd Slice for Resource Control
Before diving into configuration, it helps to understand what a slice is. In systemd, a slice is a hierarchical unit that organizes other units (like services) and allows you to apply resource controls collectively. Instead of setting limits on each service individually, I define a slice — say, web-services.slice — and assign services to it. Then I apply memory and IO limits to the slice itself. This is cleaner and more scalable, especially when managing dozens of units.
I first started using slices after seeing memory spikes from a logging agent that wasn’t capped. Once I moved it into a dedicated slice with a 512M memory ceiling, the host remained stable even during log floods. The key is that systemd enforces these limits via cgroups v2, which is the default on modern distributions.
Creating a Custom Slice with Limits
To create a slice with memory and IO limits, I create a drop-in file or a full unit file. Here’s how I do it for a slice called restricted.slice:
[Slice]
MemoryMax=512M
IOReadBandwidthMax=/dev/sda 50M
IOWriteBandwidthMax=/dev/sda 30M
I save this as /etc/systemd/system/restricted.slice.d/limits.conf and reload systemd:
sudo systemctl daemon-reload
Then I can assign any service to this slice using Slice=restricted.slice in its service file. For example, to limit a custom app:
[Service]
Slice=restricted.slice
After editing, I restart the service:
sudo systemctl restart my-app.service
Verifying That Limits Are Applied
Once the service is running, I check if the limits are active. The easiest way is to look at the cgroup v2 filesystem:
cat /sys/fs/cgroup/system.slice/restricted.slice/memory.max
This should show 536870912 (512M in bytes). For IO, I check:
cat /sys/fs/cgroup/system.slice/restricted.slice/io.max
If the limits aren’t applying, I verify that the system is using cgroups v2. I can check with:
mount | grep -E 'cgroup2'
If it’s not mounted, I may need to add systemd.unified_cgroup_hierarchy=1 to the kernel boot parameters — something I’ve had to do on older Ubuntu LTS releases.
Monitoring Slice Usage Over Time
Setting limits is only half the battle; I also monitor usage to tune them properly. I use systemd-cgtop for real-time views:
sudo systemd-cgtop
This shows memory and IO usage per slice, updated every few seconds. For longer-term tracking, I rely on metrics exported via Prometheus node exporter, which collects cgroup v2 stats. I’ve set up alerts when a slice hits 90% of its memory limit for more than five minutes — that usually means I need to investigate a leak or increase the limit.
As I mentioned before in my post about <https://furkanikkan.com/urun/systemd-resolved-ile-dns-over-tls-ve-dnssec-yapilandirma-kilavuzu-102>, combining systemd features with observability gives me confidence in production systems.
Common Pitfalls and Warnings
One mistake I made early on was applying IO limits to the wrong block device. If your system uses LVM or MDADM, you need to specify the underlying device (like /dev/sda) or use a wildcard. I now test with a small value first and observe the impact.
Another warning: setting MemoryMax too low can cause services to crash with OOM kills. I always start high (like 2G) and gradually reduce while watching logs. Also, remember that slices are hierarchical — limits on a parent slice affect all children.
Finally, avoid mixing cgroups v1 and v2 configurations. If you’re using legacy tools like cgconf, they won’t work reliably. Stick to systemd’s native interface.
When to Use Slices Over Service-Level Limits
I prefer slices when:
- I want to limit a group of related services (e.g., all monitoring agents)
- I’m deploying via Ansible or Puppet and want consistent grouping
- I need to see aggregate usage in tools like
systemd-cgtop
For single-service limits, I still set them directly in the service file. But for isolation at scale, slices are my go-to.
Conclusion
Using systemd Slice for memory and IO isolation has made my hosts more predictable and resilient. It’s not about cutting corners — it’s about setting boundaries so that one service can’t destabilize the whole system. Once you get used to the workflow — create the slice, apply limits, assign services, monitor — it becomes just another part of reliable Linux operations.
If you’re running multi-tenant workloads or just want to stop a runaway backup job from killing your database, give slices a try. Start small, test in staging, and scale from there.
Cover image: Lenharth Systems · CC0 (Openverse / kamu malı) · https://stocksnap.io/photo/cpu-processor-SPQ6DQLFLF
