Центр Диагностики & База Системных Ошибок

Решения для Windows Server, Active Directory, 1С, СУБД, Linux, Cisco, MikroTik и IP-телефонии.

⚠️ Важная информация Все материалы, инструкции, команды и скрипты предоставлены исключительно в ознакомительных целях. Их применение может повлиять на работу операционной системы, баз данных и сетевого оборудования. Перед выполнением действий обязательно создайте резервную копию. При отсутствии необходимой квалификации обратитесь к ИТ-специалистам.
LINUX-SYSTEMD-CGROUPSV2-TUNE Linux / DevOps

Гайд: Ограничение ресурсов для сервисов через systemd cgroups v2 (MemoryMax, CPUQuota, IOWeight)

Обновлено: 21.08.2026  ·  Официальная база знаний

Архитектура единой иерархии Control Groups v2 (Unified cgroups v2)

Подсистема ядра Linux cgroups v2 (Control Groups) в сочетании с systemd обеспечивает изоляцию и квотирование аппаратных ресурсов сервера (CPU, RAM, Disk I/O, Network, PIDs) между процессами и службами. В отличие от устаревшей раздельной модели cgroups v1, вторая версия реализует единую древовидную иерархию (Unified Hierarchy) с контроллерами memory.max, cpu.max, io.weight, исключая конфликты распределения ресурсов. Если для ресурсоемкого сервиса не настроены лимиты, возникают критические сбои:

  • Эффект «Шумного соседа» (Noisy Neighbor): Фоновый воркер или скрипт аналитики утилизирует 100% ядер процессора, блокируя обслуживание клиентов основным веб-сервером;
  • Неконтролируемый OOM-Kill: Утечка памяти в одном приложении приводит к тому, что ядро Linux уничтожает СУБД (PostgreSQL/MySQL), работающую на этом же хосте;
  • Дисковое голодание (I/O Starvation): Неприоритетный бэкап забивает очередь дискового ввода-вывода.

Бизнес-риски

Непредсказуемые отказы продуктовых сервисов, каскадная деградация производительности кластера, перерасход ресурсов инфраструктуры.

Сравнение ключевых директив cgroups v2 в systemd

Директива systemdКонтроллер ядра cgroups v2Поведение при достижении лимита
MemoryMax=memory.maxЖесткий лимит. При попытке превысить — мгновенный OOM-Kill внутри группы.
MemoryHigh=memory.highМягкий троттлинг. Ядро агрессивно сбрасывает кэш и замедляет процессы группы без их убийства.
CPUQuota=cpu.max (CFS Quota)Ограничение процессорного времени (например, 200% = максимум 2 ядра CPU).
CPUWeight=cpu.weight (CFS Shares)Относительный вес приоритета процессора при конкуренции (от 1 до 10000).
IOWeight=io.weight (BFQ)Относительный приоритет дискового ввода-вывода (от 1 до 10000).
TasksMax=pids.maxЗащита от Fork-бомб (максимальное количество потоков/процессов в юните).

Регламент настройки квот и изоляции ресурсов сервисов

Сценарий 1: Проверка активации cgroups v2 в ядре

# Проверка типа смонтированной файловой системы cgroups:
mount -t cgroup2
# Ожидаемый вывод: cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)

# Если используется cgroups v1 -> добавьте в /etc/default/grub параметр:
# GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1"
# и выполните sudo update-grub && sudo reboot

Сценарий 2: Применение ограничений через Drop-In переопределения (systemctl edit)

Настройте безопасные лимиты для сервиса без прямого редактирования основного файла пакета:

# 1. Открытие редактора переопределений для сервиса (например, my-worker.service):
sudo systemctl edit my-worker.service

# 2. Внесите конфигурацию ограничений в секцию [Service]:
[Service]
# Ограничение памяти: мягкий троттлинг на 2 ГБ, жесткий стоп на 2.5 ГБ:
MemoryHigh=2G
MemoryMax=2.5G

# Ограничение процессора: не более 1.5 ядер CPU (150%):
CPUQuota=150%
# Пониженный приоритет CPU при конкуренции с веб-сервером:
CPUWeight=50

# Пониженный приоритет дискового ввода-вывода:
IOWeight=20

# Ограничение максимального количества процессов:
TasksMax=500

# Настройка защиты от убийства системным OOM (значение от -1000 до 1000, где -1000 = запрет убийства):
OOMScoreAdjust=500  # Делаем этот рабочий процесс первой жертвой при нехватке памяти в ОС

# 3. Примените изменения:
sudo systemctl daemon-reload
sudo systemctl restart my-worker.service

Сценарий 3: Динамическое изменение лимитов на лету (systemctl set-property)

Изменение квот без перезапуска работающего продуктового процесса:

# Установить лимит CPUQuota = 50% прямо сейчас и сохранить на постоянной основе:
sudo systemctl set-property my-worker.service CPUQuota=50% MemoryMax=1G

Сценарий 4: Мониторинг потребления ресурсов группами через systemd-cgtop

# Интерактивный мониторинг потребления CPU, RAM и I/O по cgroups в реальном времени:
systemd-cgtop -m

Типовые ошибки администраторов

  • Установка MemoryMax без MemoryHigh: При резких скачках нагрузки процесс мгновенно уничтожается OOM-киллером вместо мягкого освобождения кэшей.
  • Использование CPUQuota=50% на многопоточном сервисе: 50% означает половину времени ОДНОГО ядра, что может критически замедлить многопоточное Java/Go-приложение. Для 4-ядерного выделения указывайте CPUQuota=400%.
Фоновые задачи «вешают» весь сервер или утечки памяти крашат базы данных?
Инженеры ITSTM настроят единую модель квотирования cgroups v2, выделят гарантированные ресурсы под критические СУБД и изолируют вспомогательные микросервисы.
Практический опыт инженера: Всегда используйте MemoryHigh в качестве буфера безопасности перед MemoryMax. Когда потребление достигает MemoryHigh, ядро начинает оказывать обратное давление (Backpressure), принудительно заставляя процесс освобождать неиспользуемые страницы и замедляя выделение новой памяти, что позволяет избежать аварийного перезапуска сервиса.

Частые вопросы (FAQ)

Как посмотреть реальное потребление памяти конкретной cgroup из ядра?

Проверьте псевдофайл: cat /sys/fs/cgroup/system.slice/my-worker.service/memory.current.

В чем разница между MemoryMax и MemorySwapMax?

MemoryMax ограничивает физическую оперативную память (RAM), а MemorySwapMax задает максимальный объем swap-пространства, который разрешено использовать процессам данной группы.

Как защитить базу данных MySQL / PostgreSQL от OOM-Killer через systemd?

В секции [Service] unit-файла базы данных укажите OOMScoreAdjust=-900. Ядро будет уничтожать любые другие процессы, защищая демон СУБД до последнего.

Что произойдет, если процесс внутри cgroup превысит TasksMax?

Попытки вызова fork() или pthread_create() начнут возвращать ошибку EAGAIN (Resource temporarily unavailable), предотвращая исчерпание системной таблицы PID.