Ограничение ресурсов в systemd: настройка без сюрпризов
CPUQuota ограничит долю процессора, MemoryMax поставит жёсткий потолок памяти, а TasksMax — число задач в сервисе. Показываем, как выбрать способ настройки, проверить поддержку cgroup v2 и не уронить рабочий процесс слишком низким лимитом.

В systemd можно ограничить CPU, память и число задач сервиса, но неверный лимит способен превратить защиту от перегрузки в причину перезапусков и ошибок. Ниже — практическая настройка для systemd 252 и новее на cgroup v2: что выбрать для постоянного сервиса, как проверить результат и какие значения не стоит ставить вслепую.
Сначала проверьте систему и выберите способ
Примеры рассчитаны на systemd 252+ и единую иерархию cgroup v2. Уточните версию командой systemctl --version, а тип файловой системы cgroup — командой stat -fc %T /sys/fs/cgroup. Для cgroup v2 ожидается ответ cgroup2fs. Если у вас systemd старее или вы видите другой ответ, сверяйтесь с документацией именно своей системы: доступность контроллеров зависит и от ядра, и от конфигурации загрузки.
В примере ниже сервис называется myapp.service. Замените имя на настоящее: его можно найти через systemctl list-units --type=service. Для постоянной настройки обычно подходит drop-in-файл — отдельное дополнение к unit, которое переживает перезагрузку и не меняет пакетный файл службы.
- CPUQuota задаёт верхнюю долю CPU в процентах. Это потолок, а не обещание выделить такую мощность.
- MemoryHigh — уровень, после которого ядро начинает сильнее ограничивать потребление памяти. Это рабочий сигнал давления, а не жёсткая граница.
- MemoryMax — жёсткий предел памяти cgroup. При его достижении возможна реакция OOM killer, поэтому процесс может завершиться.
- TasksMax ограничивает число задач в cgroup; потоки тоже учитываются. Слишком низкое значение может помешать создать новые потоки или процессы.
Термин. Cgroup — группа процессов, для которой ядро Linux учитывает и регулирует ресурсы. systemd помещает управляемый сервис в такую группу; лимит действует не только на главный процесс, но и на процессы-потомки.
Три способа установить лимиты
| Способ | Когда подходит | Цена и риск |
|---|---|---|
Drop-in через systemctl edit | Постоянный сервис, настройки которого нужно хранить отдельно от поставляемого unit-файла | Настройка переживёт перезагрузку; изменение обычно требует перезапуска сервиса |
systemctl set-property | Быстро изменить лимит существующего сервиса командой, в том числе при диагностике | Без --runtime изменение сохраняется. Легко потерять связь с системой управления конфигурацией |
| Unit-файл собственного сервиса | Unit принадлежит вашему проекту и создаётся при развёртывании | Удобно хранить настройки рядом с конфигурацией проекта; нужно следить, чтобы деплой не перезаписывал значения |
Не редактируйте файлы unit, установленные пакетным менеджером: обновление пакета может затереть правки. Для уже существующего сервиса начните с drop-in. Если лимиты должны воспроизводиться на всех серверах, внесите их в источник конфигурации, который использует ваша команда.
Рекомендуемый вариант: drop-in для сервиса
Откройте дополнение командой sudo systemctl edit myapp.service и добавьте настройки в секцию [Service]. Примерные цифры ниже показывают синтаксис, но не являются универсальным профилем: подберите их по нагрузочным замерам и запасу до отказа.
[Service]
CPUQuota=150%
MemoryHigh=700M
MemoryMax=900M
TasksMax=200
CPUQuota=150% не закрепляет за сервисом полтора ядра постоянно: он лишь ограничивает максимальное потребление CPU. MemoryHigh стоит выставлять ниже MemoryMax, чтобы сначала получить давление на память, а не сразу упереться в жёсткий предел. TasksMax выбирайте с учётом пикового числа потоков и дочерних процессов.
После сохранения перечитайте конфигурацию и примените изменения в согласованное окно: перезапуск может прервать обслуживание запросов.
sudo systemctl daemon-reload
sudo systemctl restart myapp.service
sudo systemctl show myapp.service -p CPUQuotaPerSecUSec -p MemoryHigh -p MemoryMax -p TasksMax
Проверьте вывод последней команды: значения должны соответствовать заданным лимитам. Затем убедитесь, что сервис запущен командой systemctl status myapp.service. Для дополнительной проверки текущего потребления используйте systemd-cgtop и наблюдайте за сервисом во время характерной нагрузки.
Лимит — это граница отказа, а не цель потребления. Настраивайте её по измеренному пику и проверяйте поведение сервиса, когда он подходит к границе.
Когда выбрать два других способа
Быстрая настройка через set-property
Чтобы задать свойства работающему сервису, используйте systemctl set-property:
sudo systemctl set-property myapp.service CPUQuota=150% MemoryHigh=700M MemoryMax=900M TasksMax=200
Этот вариант удобен, когда нужно быстро изменить лимит и посмотреть на результат. По умолчанию свойства сохраняются; с параметром --runtime изменение действует только до перезагрузки. После команды всё равно проверьте показанные systemd значения и метрики приложения. Если настройки задаёт Ansible, другой менеджер конфигурации или собственный деплой, внесите изменение и туда: иначе следующий запуск управления конфигурацией может его отменить.
Настройка в unit-файле проекта
Если вы сами поставляете unit, те же параметры можно хранить в его секции [Service]. Это удобно для повторяемого развёртывания, но источник истины должен быть один: правка только на сервере разойдётся с репозиторием или шаблоном деплоя. Для сторонних пакетных служб используйте drop-in, а не заменяйте оригинальный файл.
Что ломается при слишком жёстких лимитах
- Сервис регулярно перезапускается. Проверьте журналы через
journalctl -u myapp.serviceи сопоставьте момент остановки с потреблением памяти. НизкийMemoryMaxможет вызвать завершение процесса; сам по себе лимит не гарантирует, что приложение корректно обработает нехватку ресурсов. - Запросы стали медленнее, хотя CPU не заполнен.
CPUQuotaограничивает пиковое использование процессора. Сравните задержки и фактическое потребление до и после настройки; не путайте потолок с гарантированной долей CPU. - Не создаются потоки или дочерние процессы. Проверьте
TasksMaxи штатное пиковое число задач приложения. Учитывайте именно весь сервис, включая его дочерние процессы и потоки. - Лимит не виден или действует не так, как ожидалось. Проверьте версию systemd, тип cgroup, имя unit и итоговую конфигурацию командой
systemctl cat myapp.service. Убедитесь также, что конфигурацию после изменения перечитали и сервис перезапустили.
Не пытайтесь заменить системные ограничения командой ulimit: она задаёт ограничения процессу и его окружению, а не настраивает те же свойства cgroup для всего systemd-сервиса.
Что делать дальше
Снимите базовые показатели без лимитов: потребление CPU и памяти, число задач и задержки сервиса на обычной и пиковой нагрузке. Затем установите консервативные границы, проверьте поведение в тестовой среде и наблюдайте за журналами и метриками после выкладки. Инвалидация кэша и настройка приоритетов CPU — отдельные темы; здесь разбирались только лимиты ресурсов.
Задачи: математика, физика, химия: Разбор задачи по шагам с проверкой и похожей задачей
Спросить за 10 ₽Источники: systemd.resource-control — документация по управлению ресурсами, systemctl — документация по управлению systemd
Частые вопросы
Можно ли скопировать значения CPUQuota и MemoryMax из примера?
Нужно ли перезапускать сервис после изменения лимитов?
Что будет, если MemoryMax окажется ниже нужного?
Сработают ли эти настройки на другой версии systemd?
Почему лимит не появился в systemctl show?
Можно ли ограничить только один процесс внутри сервиса?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.