Вопрос или проблема
Я знаю о ulimit и понимаю, как ограничить память для процесса, который я явно запускаю или запускаю с помощью скрипта. Но в данном случае у меня есть служба, которая управляется и запускается systemd.
Как я могу ограничить её максимальное использование памяти и заставить её завершаться (или, что ещё лучше: предотвратить выделение памяти (возвращать NULL для malloc
/ realloc
)), когда она достигает предела использования памяти?
Страница man для systemd.exec
содержит список инструкций LimitXXXX и удобную таблицу, сравнивающую их с опциями ulimit
, с помощью системного вызова setrlimit()
.
Чтобы ограничить всё адресное пространство процесса (ulimit -v
), используйте LimitAS=
. В противном случае, чтобы ограничить только стек (ulimit -s
), используйте LimitSTACK=
, или сегмент данных (ulimit -d
), используйте LimitDATA=
.
Согласно странице man для setrlimit()
, эти ограничения приведут к неудаче при выделении дополнительной памяти. STACK и AS завершат программу с помощью sigsegv, если лимит будет достигнут, а стеку нужно будет расти (и программа не обрабатывала это).
Systemd поддерживает ограничение использования памяти с помощью параметра MemoryLimit, как описано здесь: https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html
То, как система обрабатывает ситуацию, когда максимальная разрешённая память (на службу) исчерпывается, зависит как от реализации cgroups, так и от того, как systemd реализует управление ресурсами; я предполагаю, что процесс будет завершён (с помощью OOM killer).
Для ограничений, аналогичных ulimit:
man systemd.exec
...
LimitAS=(как ulimit -v)
...
LimitRSS=(как ulimit -m)
...
Начиная с версии systemd 231
, вы можете указать:
[Service]
MemoryHigh=750M
MemoryMax=1G
При превышении MemoryHigh
процессы значительно замедляются, и память может быть изъята. Если использование памяти не может быть удержано в пределах ограничения MemoryMax
, внутри юнита вызывается киллер из-за исчерпания памяти.
Это требует включения учёта памяти, например, в системном конфиге /etc/systemd/system.conf
:
MemoryAccounting=yes
Смотрите документацию для получения дополнительных сведений.
Ответ или решение
Чтобы ограничить использование памяти сервисом, управляемым systemd, вы можете использовать несколько параметров, которые предоставляет systemd для настройки ресурсов. Вот пошаговое руководство по установке ограничений памяти для такого сервиса.
Шаг 1: Использование параметров systemd для ограничения памяти
В файле конфигурации вашего сервиса, который обычно находится в /etc/systemd/system/
, для ограничения памяти можно использовать следующие параметры:
-
MemoryHigh= – сам параметр указывает на уровень использования памяти, после которого процессы могут быть замедлены и лишены части памяти. Это не жесткий предел, а скорее предупреждение о том, что использование памяти высокое.
-
MemoryMax= – этот параметр устанавливает жесткий предел использования памяти. Если процесс превышает этот лимит, systemd вызовет механизм OOM killer (Out Of Memory), который может завершить данный процесс.
Пример конфигурации
Добавьте следующие строки в секцию [Service]
вашего unit-файла:
[Service]
MemoryHigh=750M
MemoryMax=1G
В приведенном выше примере сервису будет разрешено использовать до 750 МБ памяти, и если оно превысит 1 ГБ, процесс будет завершён.
Шаг 2: Включение учёта памяти
Для того чтобы указанные ограничения работали, необходимо включить учёт памяти в конфигурации systemd. Это можно сделать, редактируя файл /etc/systemd/system.conf
и добавив или изменив строчку:
MemoryAccounting=yes
Шаг 3: Перезагрузка systemd
После внесения изменений в конфигурацию, выполните команды:
sudo systemctl daemon-reload
sudo systemctl restart your-service-name.service
Дополнительная информация
Для справки вы можете ознакомиться с документацией, доступной по следующим ссылкам:
С помощью этих настроек вы сможете управлять памятью вашего сервиса, предотвращая его переполнение и возникающие проблемы из-за чрезмерного использования ресурсов.