Короткий ответ
Активный swap сам по себе не авария: Ubuntu часто имеет swap-файл и редкие si/so. Авария — когда MemAvailable падает, PSI full растёт, диск swap молотит, SSH начинает отвечать секундами. Сначала докажите давление: free -h, vmstat 1, cat /proc/pressure/memory. Потом решите: снизить consumers (кэш приложения, workers), добавить RAM, не swapoff под нагрузкой и не vm.swappiness=0 как магическая кнопка.
Хост host.example (10.0.20.10), пользователь admin.
Симптомы и как отличить
free -h:availableсотни МБ приtotal8 ГБ,swap usedрастёт;vmstatколонкиsi/soдесятки тысяч блоков в секунду;- нагрузка «как CPU», но
mpstatпоказывает iowait, а не usr — swapping; - пользователи: таймауты, PHP 502, postgres
terminating connection due to administrator commandпосле OOM.
| Наблюдение | Скорее |
|---|---|
| cache большой, available тоже большой | норма, page cache |
| available мал, cache мал, swap used растёт | настоящая нехватка |
| OOM в dmesg | уже убийство, не «ещё потерпеть» — OOM |
| hang без si/so | зависание |
Возможные причины
- Утечка в приложении / рост heap JVM без
-Xmx. - Слишком много
php-fpmpm.max_children × memory_limit. - PostgreSQL
shared_buffers+work_mem× соединений. - File cache + анонимная память на узком хосте — ядро вытесняет anon в swap.
- tmpfs
/tmpзабит (это RAM). systemd-oomdещё не сработал, PSI уже красный.- Swap на том же медленном диске, что и БД — двойной iowait.
Диагностика
free -h
swapon --show
cat /proc/swaps
cat /proc/meminfo
cat /proc/pressure/memory
vmstat 1 15PSI: строки some и full, поля avg10 avg60 avg300. full > 0 устойчиво — процессы стоят в ожидании памяти.
Кто ест анонимную память:
ps -eo pid,user,rss,vsz,cmd --sort=-rss | head -n 20
sudo smem -tk 2>/dev/null | head
grep -s VmRSS /proc/*/status | sort -n -k2 | tailRSS не суммируется напрямую из‑за shared; для cgroup:
systemd-cgtop -m -n 1
systemctl show app.service -p MemoryCurrent,MemoryMax,MemoryHightmpfs:
df -h -t tmpfs
sudo du -sh /tmp /dev/shm /runЕсли /tmp на диске, это не RAM — но spill туда огромных сортировок всё равно бьёт диск.
Ядро и oomd:
systemctl status systemd-oomd --no-pager
journalctl -u systemd-oomd -b --no-pager | tail
dmesg -T | grep -iE 'oom|killed process' | tailРешение
Сценарий A. Понятный потребитель, сервис можно снизить
Уменьшите workers, перезапустите один unit после дампа диагностики:
sudo systemctl restart app.service
free -hЗафиксируйте MemoryMax= в drop-in, чтобы повторение упёрлось в cgroup, а не в весь хост.
Сценарий B. Нужно пережить пик
Временно остановите некритичное: batch, apt, snapshot. Не трогайте sshd и systemd-journald.
Сценарий C. Swap слишком маленький или на переполненном диске
Добавление swap-файла — только если на диске есть место (df -h) и вы понимаете, что это костыль латентности:
df -h /
sudo fallocate -l 2G /swapfile.extra
sudo chmod 600 /swapfile.extra
sudo mkswap /swapfile.extra
sudo swapon /swapfile.extraНе кладите второй swap на тот же SSD, который уже 100% util.
Сценарий D. Хочется крутить swappiness
vm.swappiness на сервере с 32 ГБ и БД часто ставят 10, не 0. Ноль увеличивает риск жёсткого OOM. Меняйте sysctl после замеров PSI, не вместо них.
Сценарий E. Утечка подтверждена
Дамп heap/coredump, откат релиза. Reboot очистит RAM на часы — это не фикс.
Как выбрать шаг: рестарт, MemoryMax, RAM, swap
Порядок безопасных шагов после того, как PSI full ненулевой:
- Зафиксировать топ RSS и cgroup MemoryCurrent в заявку.
- Остановить расходный batch (
apt, backup, CI), не sshd. - Если есть явный unit-утечка — рестарт его с дампом.
- Поставить временный
MemoryHigh/MemoryMax, чтобы не убить хост. - Добавлять RAM на гипервизоре, если это постоянный рабочий набор, а не утечка.
- Swap — только чтобы пережить пик на диске, где
iostatне в 100% util.
На Ubuntu 22.04 systemd-oomd включён в desktop-образах чаще, чем на minimal server; на 24.04 server проверяйте systemctl is-enabled systemd-oomd. Если oomd выключен, давление дольше живёт в swap и выглядит как «диск умер» из‑за iowait.
MemAvailable учитывает reclaimable cache. Если Available 2 ГБ, а free колонка 100 МБ — не паникуйте и не drop_caches. Если Available 80 МБ и si/so кипят — паникуйте.
Для PostgreSQL смотрите shared_buffers плюс work_mem × активных сортировок. Формула «25% RAM в shared_buffers» на 8 ГБ хосте вместе с java рядом даёт OOM. Считайте сумму сервисов, не каждый по отдельности как на выделенном сервере.
Как проверить, что проблема устранена
free -h
cat /proc/pressure/memory
vmstat 1 10
swapon --show
ssh admin@10.0.20.10 'uptime'si/so около нуля под типичной нагрузкой, available с запасом (ориентир >15–20% RAM для смешанных узлов). Приложение отвечает без 502.
Если не помогло
- После рестарта RSS снова растёт линейно: утечка, профилируйте код.
- PSI полный,
freeврёт из‑за huge pages/hugepages не освобождённых:grep Huge /proc/meminfo. - Гость видит ballooning гипервизора: смотрите хост.
- Уже есть
Killed process— статья OOM, не эта.
Профилактика
- Мониторинг
MemAvailable, PSIfull, swap I/O отдельно. MemoryMaxна потенциально дырявых unit.- Размер swap: аварийный тормоз, не «вторая RAM».
- Не запускать CI-раннеры на том же 4 ГБ узле, что и postgres.
FAQ
Почему cache «съел» всю память?
Так задумано. Ядро отдаст cache под anon. Смотрите available.
Нужен ли swap на машине с 64 ГБ?
Небольшой swap полезен для редких пиков и чтобы oom killer получил время. Нулевой swap = более жёсткий OOM.
smem не установлен
ps + cgroup достаточно. Не ставьте случайные PPA в инцидент.
Можно ли echo 3 > drop_caches?
Это сбросит page cache и на секунды улучшит free, ухудшив I/O. Не диагностика давления anon.
systemd-oomd убил ssh?
Редко, если ssh в том же cgroup user.slice под давлением. Проверьте oomctl / логи oomd и не держите тяжёлые job в user-сессии admin.