2.3. Modifying Control Groups

Each persistent unit supervised by systemd has a unit configuration file in the /usr/lib/systemd/system/ directory. To change parameters of a service unit, modify this configuration file. This can be done either manually or from the command-line interface by using the systemctl set-property command.

2.3.1. Setting Parameters from the Command-Line Interface

The systemctl set-property command allows you to persistently change resource control settings during the application runtime. To do so, use the following syntax as root:
~]# systemctl set-property name parameter=value
Replace name with the name of the systemd unit you wish to modify, parameter with a name of the parameter to be changed, and value with a new value you want to assign to this parameter.
Not all unit parameters can be changed at runtime, but most of those related to resource control may, see Section 2.3.2, “Modifying Unit Files” for a complete list. Note that systemctl set-property allows you to change multiple properties at once, which is preferable over setting them individually.
The changes are applied instantly, and written into the unit file so that they are preserved after reboot. You can change this behavior by passing the --runtime option that makes your settings transient:
~]# systemctl set-property --runtime name property=value

Example 2.2. Using systemctl set-property

To limit the CPU and memory usage of httpd.service from the command line, type:
~]# systemctl set-property httpd.service CPUShares=600 MemoryLimit=500M
To make this a temporary change, add the --runtime option:
~]# systemctl set-property --runtime httpd.service CPUShares=600 MemoryLimit=500M

2.3.2. Modifying Unit Files

Systemd service unit files provide a number of high-level configuration parameters useful for resource management. These parameters communicate with Linux cgroup controllers, that have to be enabled in the kernel. With these parameters, you can manage CPU, memory consumption, block IO, as well as some more fine-grained unit properties.

Managing CPU

The cpu controller is enabled by default in the kernel, and consequently every system service receives the same amount of CPU time, regardless of how many processes it contains. This default behavior can be changed with the DefaultControllers parameter in the /etc/systemd/system.conf configuration file. To manage CPU allocation, use the following directive in the [Service] section of the unit configuration file:
CPUShares=value
Replace value with a number of CPU shares. The default value is 1024. By increasing the number, you assign more CPU time to the unit. Setting the value of the CPUShares parameter automatically turns CPUAccounting on in the unit file. Users can thus monitor the usage of the processor with the systemd-cgtop command.
The CPUShares parameter controls the cpu.shares control group parameter. See the description of the cpu controller in Controller-Specific Kernel Documentation to see other CPU-related control parameters.

Example 2.3. Limiting CPU Consumption of a Unit

To assign the Apache service 1500 CPU shares instead of the default 1024, create a new /etc/systemd/system/httpd.service.d/cpu.conf configuration file with the following content:
[Service]
CPUShares=1500
To apply the changes, reload systemd's configuration and restart Apache so that the modified service file is taken into account:
~]# systemctl daemon-reload
~]# systemctl restart httpd.service
CPUQuota=value
Replace value with a value of CPU time quota to assign the specified CPU time quota to the processes executed. The value of the CPUQuota parameter, which is expressed in percentage, specifies how much CPU time the unit gets at maximum, relative to the total CPU time available on one CPU.
Values higher than 100% indicate that more than one CPU is used. CPUQuota controls the cpu.max attribute on the unified control group hierarchy, and the legacy cpu.cfs_quota_us attribute. Setting the value of the CPUQuota parameter automatically turns CPUAccounting on in the unit file. Users can thus monitor the usage of the processor with the systemd-cgtop command.

Example 2.4. Using CPUQuota

Setting CPUQuota to 20% ensures that the executed processes never get more than 20% CPU time on a single CPU.
To assign the Apache service CPU quota of 20%, add the following content to the /etc/systemd/system/httpd.service.d/cpu.conf configuration file:
[Service]
CPUQuota=20%
To apply the changes, reload systemd's configuration and restart Apache so that the modified service file is taken into account:
~]# systemctl daemon-reload
~]# systemctl restart httpd.service

Managing Memory

To enforce limits on the unit's memory consumption, use the following directives in the [Service] section of the unit configuration file:
MemoryLimit=value
Replace value with a limit on maximum memory usage of the processes executed in the cgroup. Use suffixes K, M, G, or T to identify Kilobyte, Megabyte, Gigabyte, or Terabyte as the unit of measurement. Also, the MemoryAccounting parameter has to be enabled for the unit.
The MemoryLimit parameter controls the memory.limit_in_bytes control group parameter. For more information, see the description of the memory controller in Controller-Specific Kernel Documentation.

Example 2.5. Limiting Memory Consumption of a Unit

To assign a 1GB memory limit to the Apache service, modify the MemoryLimit setting in the /etc/systemd/system/httpd.service.d/cpu.conf unit file:
[Service]
MemoryLimit=1G
To apply the changes, reload systemd's configuration and restart Apache so that the modified service file is taken into account:
~]# systemctl daemon-reload
~]# systemctl restart httpd.service

Managing Block IO

To manage the Block IO, use the following directives in the [Service] section of the unit configuration file. Directives listed below assume that the BlockIOAccounting parameter is enabled:
BlockIOWeight=value
Replace value with a new overall block IO weight for the executed processes. Choose a single value between 10 and 1000, the default setting is 1000.
BlockIODeviceWeight=device_name value
Replace value with a block IO weight for a device specified with device_name. Replace device_name either with a name or with a path to a device. As with BlockIOWeight, it is possible to set a single weight value between 10 and 1000.
BlockIOReadBandwidth=device_name value
This directive allows you to limit a specific bandwidth for a unit. Replace device_name with the name of a device or with a path to a block device node, value stands for a bandwidth rate. Use suffixes K, M, G, or T to specify units of measurement. A value with no suffix is interpreted as bytes per second.
BlockIOWriteBandwidth=device_name value
Limits the write bandwidth for a specified device. Accepts the same arguments as BlockIOReadBandwidth.
Each of the aforementioned directives controls a corresponding cgroup parameter. For other CPU-related control parameters, see the description of the blkio controller in Controller-Specific Kernel Documentation.

Note

Currently, the blkio resource controller does not support buffered write operations. It is primarily targeted at direct I/O, so the services that use buffered write will ignore the limits set with BlockIOWriteBandwidth. On the other hand, buffered read operations are supported, and BlockIOReadBandwidth limits will be applied correctly both on direct and buffered read.

Example 2.6. Limiting Block IO of a Unit

To lower the block IO weight for the Apache service accessing the /home/jdoe/ directory, add the following text into the /etc/systemd/system/httpd.service.d/cpu.conf unit file:
[Service]
BlockIODeviceWeight=/home/jdoe 750
To set the maximum bandwidth for Apache reading from the /var/log/ directory to 5MB per second, use the following syntax:
[Service]
BlockIOReadBandwith=/var/log 5M
To apply your changes, reload systemd's configuration and restart Apache so that the modified service file is taken into account:
~]# systemctl daemon-reload
~]# systemctl restart httpd.service

Managing Other System Resources

There are several other directives that can be used in the unit file to facilitate resource management:
DeviceAllow=device_name options
This option controls access to specific device nodes. Here, device_name stands for a path to a device node or a device group name as specified in /proc/devices. Replace options with a combination of r, w, and m to allow the unit to read, write, or create device nodes.
DevicePolicy=value
Here, value is one of: strict (only allows the types of access explicitly specified with DeviceAllow), closed (allows access to standard pseudo devices including /dev/null, /dev/zero, /dev/full, /dev/random, and /dev/urandom) or auto (allows access to all devices if no explicit DeviceAllow is present, which is the default behavior)
Slice=slice_name
Replace slice_name with the name of the slice to place the unit in. The default is system.slice. Scope units cannot be arranged in this way, since they are tied to their parent slices.
ExecStartPost=command
Currently, systemd supports only a subset of cgroup features. However, as a workaround, you can use the ExecStartPost= option along with setting the memory.memsw.limit_in_bytes parameter in order to prevent any swap usage for a service. For more information on ExecStartPost=, see the systemd.service(5) man page.

Example 2.7. Configuring Cgroup Options

Imagine that you wish to change the memory.memsw.limit_in_bytes setting to the same value as the unit's MemoryLimit= in order to prevent any swap usage for a given example service.
ExecStartPost=/bin/bash -c "echo 1G > /sys/fs/cgroup/memory/system.slice/example.service/memory.memsw.limit_in_bytes"
To apply the change, reload systemd configuration and restart the service so that the modified setting is taken into account:
~]# systemctl daemon-reload
~]# systemctl restart example.service