On production Ubuntu servers hosting database engines, web servers, background batch workers, and scheduled backup scripts, unconstrained background processes can easily monopolise CPU cores. When a data processing worker consumes 100% of available processor time, critical user-facing services can suffer severe latency spikes and connection timeouts.
Rather than relying on legacy Unix process priority utilities (like nice and renice), modern Ubuntu installations manage system resources through systemd and the Linux kernel Control Groups version 2 (cgroups v2) architecture. By configuring CPUQuota and CPUWeight directives directly inside systemd unit drop-in files, administrators can precisely limit processor saturation and establish predictable resource contention rules.
Understanding CPUQuota vs CPUWeight in cgroups v2
Systemd provides two distinct mechanisms for managing CPU distribution:
- CPUQuota: Enforces a strict, hard maximum ceiling on the percentage of CPU time a service can consume within a given measurement interval. For example,
CPUQuota=50%restricts a service to half of one CPU core, whereasCPUQuota=200%permits execution across up to two full CPU cores. Even if other cores are completely idle, the process cannot exceed this absolute threshold. - CPUWeight: Defines a relative proportional share of CPU resources allocated to a service during periods of CPU contention. Values range from 1 to 10000 (with a default value of 100). If two services experience heavy workloads simultaneously, a service with
CPUWeight=200receives twice as much processor time as a service withCPUWeight=100. When no contention exists, services can utilise available spare capacity freely.
Configuring CPU Limits Using Systemd Drop-in Overrides
Never edit vendor unit files located in /lib/systemd/system/ directly, as package upgrades will overwrite your changes. Instead, create persistent configuration drop-ins using systemctl edit:
- Open a terminal on your Ubuntu server.
- Execute the
systemctl editcommand targeting your service (for example, a worker service nameddata-worker.service):sudo systemctl edit data-worker.service - In the text editor, insert your resource constraints under the
[Service]section:[Service] CPUAccounting=yes CPUQuota=150% CPUWeight=50 - Save the file and exit the editor. Systemd automatically creates a persistent drop-in file at
/etc/systemd/system/data-worker.service.d/override.confand reloads its daemon configuration. - Restart the service to enforce the new resource constraints:
sudo systemctl restart data-worker.service
Verifying Enforced Directives with systemctl show
To confirm that systemd has parsed and applied your cgroup directives successfully, query the service properties:
systemctl show data-worker.service -p CPUQuotaPerSecUSec -p CPUWeight
The output will display the active values. For instance, a 150% quota displays as CPUQuotaPerSecUSec=1s 500ms, confirming that the service is restricted to 1.5 seconds of CPU time per elapsed second.
Applying Ephemeral CPU Limits on Running Services
If an active service suddenly experiences an unexpected workload surge and you need to restrict its CPU usage immediately without restarting it, use systemctl set-property:
sudo systemctl set-property data-worker.service CPUQuota=75%
This command dynamically adjusts the kernel cgroup controller on the fly. To make the adjustment temporary until the next system reboot, append the --runtime flag.
Monitoring cgroup Resource Utilisation with systemd-cgtop
To audit live CPU consumption across all systemd services and verify that limits are enforced:
systemd-cgtop -m
This top-like utility displays real-time CPU usage, memory consumption, and task counts broken down by system slice and service unit, allowing you to observe services throttled against their configured CPUQuota thresholds.