Коли пам’ять закінчується, ядро запускає жорсткий OOM-killer. Але systemd-oomd реагує раніше й м’якше: моніторить тиск пам’яті (PSI), приймає рішення на рівні cgroup та допомагає утримати систему живою. Нижче — як увімкнути його, налаштувати політики, акуратно протестувати та зберегти log-файли Linux для аналізу. Усе робимо через термінал Linux і з прицілом на оптимізацію продуктивності.

Перевірка вимог і стану

Systemd-oomd потребує ядра з PSI та cgroup v2. Перевірте оточення:

# Чи активний cgroup v2 (має бути cgroup2)
mount | grep cgroup2 || cat /sys/fs/cgroup/cgroup.controllers

# Версія systemd (бажано 248+)
systemd --version

# Статус служби oomd
systemctl status systemd-oomd.service --no-pager

Якщо служба не активна — увімкніть її:

sudo systemctl enable --now systemd-oomd.service

Якщо у вас старий дистрибутив без cgroup v2 за замовчуванням — перейдіть на сучасне ядро/реліз або вмикайте systemd.unified_cgroup_hierarchy=1 у GRUB (потребує перезавантаження).

Базове налаштування через oomd.conf.d

Глобальні пороги задаються у drop-in каталозі. Так безпечно вносити зміни і легко їх відкочувати.

sudo mkdir -p /etc/systemd/oomd.conf.d
sudo tee /etc/systemd/oomd.conf.d/99-custom.conf >/dev/null <<'EOF'
[OOM]
# Якщо середній тиск пам'яті (PSI) тримається на/вище 60% 30 секунд — діємо
DefaultMemoryPressureLimitPercent=60
DefaultMemoryPressureDurationSec=30s
# Коли swap зайнятий >= 90% — це теж тригер
DefaultSwapUsedLimitPercent=90
EOF

sudo systemctl daemon-reload
sudo systemctl restart systemd-oomd.service

Ці дефолтні пороги застосовуються для slice-ів/юнитів, де поведінка не перевизначена.

Політики на рівні slice та сервісів

Точніше керування дають опції ManagedOOM* у slice-ах і ліміти пам’яті у service-юнітах.

Приклад: агресивніша політика для user.slice

sudo mkdir -p /etc/systemd/system/user.slice.d
sudo tee /etc/systemd/system/user.slice.d/oomd.conf >/dev/null <<'EOF'
[Slice]
# Якщо тиск високий — дозволяємо oomd завершувати процеси в цьому slice
ManagedOOMMemoryPressure=kill
# Поріг PSI для цього slice (перевищення цього порогу протягом глобальної тривалості)
ManagedOOMMemoryPressureLimit=60%
# Довіряємо swap-тригеру за замовчуванням
ManagedOOMSwap=auto
EOF

sudo systemctl daemon-reload

Для системних служб налаштовуйте їхні memory-ліміти — так ви підкажете oomd і ядру, що «боляче» для конкретної служби.

# Приклад для nginx: м'який і жорсткий ліміт + мінімально гарантована пам'ять
sudo systemctl set-property nginx.service \
  MemoryHigh=2G MemoryMax=3G MemoryMin=500M

# Перевірка застосованих властивостей
systemctl show -p MemoryHigh -p MemoryMax -p MemoryMin nginx.service

Порада: для критичних сервісів (наприклад, sshd) задайте MemoryMin=, щоб зменшити їх шанс потрапити під завершення.

Тестування: симуляція браку пам’яті

Акуратно перевіримо, як спрацьовує політика. Використаємо stress-ng і паралельно подивимось PSI та журнали.

# Встановлення stress-ng (виберіть своє)
# Debian/Ubuntu:
sudo apt update && sudo apt install -y stress-ng
# Fedora:
sudo dnf install -y stress-ng
# Arch:
sudo pacman -S --noconfirm stress-ng

# У двох терміналах Linux паралельно:
# 1) Моніторинг тиску пам'яті (PSI)
watch -n1 cat /proc/pressure/memory

# 2) Перегляд логів oomd у реальному часі
sudo journalctl -u systemd-oomd -f

# 3) Запуск стресу на 60с (2 воркери, 80% RAM намагаються зайняти)
stress-ng --vm 2 --vm-bytes 80% --timeout 60s

Очікуйте у логах повідомлення на кшталт «Selected cgroup … to kill» і «Killed» з деталями про жертву, споживання пам’яті та причини. Це основа для Linux моніторинг інцидентів пам’яті.

Альтернативи та сумісність

  • earlyoom, nohang: схожі інструменти користувацького простору. Не рекомендується тримати їх одночасно з systemd-oomd — дублювання рішень.
  • Ядерний OOM-killer все одно лишається останньою лінією оборони, якщо користувацькі механізми не впоралися.
  • Без swap: oomd працює й без нього, орієнтуючись на PSI. Проте невеликий swap інколи покращує плавність під навантаженням.

GUI-спосіб (спостереження, не конфіг)

Прямого GUI для політик oomd немає. Але для візуального спостереження під час тесту можна:

  • GNOME: gnome-system-monitor (пам’ять процесів, історія).
  • KDE: plasma-systemmonitor.
  • htop: зручно дивитися RAM/Swap і навантаження CPU; у нових версіях є індикація PSI.
# Приклади встановлення моніторів
sudo apt install -y gnome-system-monitor htop || true
sudo dnf install -y gnome-system-monitor htop || true
sudo pacman -S --noconfirm gnome-system-monitor htop || true

Логування та збереження журналів

Щоб після перезавантаження зберігалися події про OOM, ввімкніть персистентні журнали journald і навчіться швидко їх фільтрувати.

# Вмикаємо постійне збереження логів journald
sudo mkdir -p /var/log/journal
sudo sed -i 's/^#\?Storage=.*/Storage=persistent/' /etc/systemd/journald.conf
sudo systemctl restart systemd-journald

# Події саме від systemd-oomd
journalctl -t systemd-oomd --since "-24h"

# Швидкий фільтр на вбивства
journalctl -t systemd-oomd | grep -i kill

Зберігайте ці виходи як артефакти інцидентів — це цінні log-файли Linux для ретроспектив і тюнінгу.

Порада від Kernelka

🛡️ Виділіть «недоторканні» ресурси критичним службам: MemoryMin= для sshd, DNS, log-агентів. Тестуйте політики на стенді або в «тихі» години, а потім поступово зменшуйте/підкручуйте пороги. Пам’ятайте про резерв конфігів і чіткі зміни з *.d drop-in — так простіше відкотитися.

FAQ

Чим systemd-oomd відрізняється від ядрового OOM-killer?

OOM-killer спрацьовує в крайньому випадку, коли пам’яті вже зовсім немає. systemd-oomd базується на PSI (тиску пам’яті) і втручається раніше, вибираючи жертви на рівні cgroup відповідно до політик.

Як захистити важливий сервіс від завершення?

Задайте MemoryMin= у його юніті та уникайте агресивних ManagedOOM* для slice, де він живе. Також розгляньте OOMPolicy=kill/stop у сервісі, якщо потрібно кероване відновлення.

Служба не стартує або «мовчить». Що перевірити?

Переконайтеся, що активний cgroup v2, версія systemd достатня, а також що немає конфліктів з іншими OOM-демонами (earlyoom/nohang). Дивіться журнали: journalctl -u systemd-oomd -b.

Чи можна повністю вимкнути systemd-oomd?

Так: sudo systemctl disable --now systemd-oomd. Але майте план B — ядровий OOM-killer все одно діятиме, і це може бути болючіше.

Swap обов’язковий?

Ні. Зі swap oomd має додатковий тригер за рівнем його зайнятості. Без swap фокусується на PSI.

Підсумок

  • Увімкніть systemd-oomd і задайте дефолтні пороги в /etc/systemd/oomd.conf.d/.
  • Налаштуйте ManagedOOM* у потрібних slice і ліміти пам’яті (MemoryHigh/Max/Min) для сервісів.
  • Протестуйте навантаженням (stress-ng), паралельно слідкуючи за PSI та журналами.
  • Увімкніть персистентні журнали journald і фільтруйте події від systemd-oomd.
  • Захистіть критичні служби через MemoryMin і поступово тюньте пороги. 🚀