Перейти до вмісту

B3. cgroups і OOM killer

середнійспирається на модуль 12, модуль 17

Модуль 12 стверджує, що malloc майже ніколи не повертає NULL, а нестача пам’яті проявляється несподіваним завершенням процесу. Тут ви відтворите це керовано, у власній контрольній групі й не ризикуючи системою.

Заразом побачите, що cgroups не є якоюсь «технологією контейнерів», а лишається звичайним механізмом ядра, доступним просто з командного рядка.

  1. Розвідка.

    Terminal window
    mount | grep cgroup2
    cat /sys/fs/cgroup/cgroup.controllers
    systemd-cgls | head -20

    Переконайтеся, що це саме v2 (одна ієрархія), і подивіться, як systemd уже розклав усі служби по групах.

  2. Власна група.

    Створіть каталог у /sys/fs/cgroup, увімкніть потрібні контролери в батьківському cgroup.subtree_control, помістіть у групу процес, записавши його PID у cgroup.procs.

    Зверніть увагу на правило внутрішніх вузлів: у v2 процеси можуть лежати лише в листках дерева. Спроба покласти процес у групу, яка має дочірні, дасть помилку — і це не баг.

  3. Обмеження процесора.

    cpu.max у форматі «квота період». Запустіть зациклений процес і подивіться в top, що він отримує рівно задану частку.

    Порівняйте з nice: nice — це вага відносно конкурентів, cpu.max — абсолютна квота (модуль 7). Процес із nice 19 на порожній машині займе 100%, процес із cpu.max 50000 100000 — рівно 50%, навіть якщо більше нікого немає.

  4. Обмеження пам’яті й OOM.

    memory.max на 64 МіБ, потім програма, що виділяє й записує пам’ять по 10 МіБ у циклі. Запис обов’язковий: без нього сторінки фізично не існують (модуль 12).

    Спостерігайте memory.current, memory.events і журнал ядра.

  5. Тиск замість убивства.

    Тепер те саме, але з memory.high замість memory.max. Процес не вбивається — його гальмують, змушуючи звільняти пам’ять. Подивіться на memory.pressure і поясніть різницю у звіті.

  6. Ввід-вивід.

    io.max на конкретний пристрій, потім dd і замір швидкості до й після.

Що треба вміти підтвердити

Section titled “Що треба вміти підтвердити”
Твердження Чим доводиться
Система на cgroups v2 mount | grep cgroup2
Ваша група існує й містить процес cat <група>/cgroup.procs
Процесор обмежено квотою, а не пріоритетом cat <група>/cpu.max + top
Пам’ять обмежено cat <група>/memory.max
OOM спрацював саме у вашій групі cat <група>/memory.events (поле oom_kill)
Ядро це зафіксувало journalctl -k --grep 'Out of memory'
Ви розумієте різницю high і max письмове пояснення у звіті

Контролери не ввімкнені. Файлів cpu.max і memory.max просто немає, поки контролер не дозволено в cgroup.subtree_control батьківської групи.

Процес не потрапляє в групу. У cgroup.procs пишеться один PID за раз, а потоки переносяться через cgroup.threads.

systemd забирає групу назад. Створювати групи руками поруч із деревом systemd можна, але надійніше робити це через systemd-run --scope.

OOM убив не того. Якщо обмеження стоїть на батьківській групі, жертву обиратимуть серед усіх нащадків. Перевірте, що ви обмежили саме той рівень, який мали на увазі.

Обмежити кількість процесів через pids.max і подивитися, що станеться з форк-бомбою :(){ :|:& };: — вона перестає бути небезпечною.