Когда на сервере внезапно «всё тормозит», а в top или htop наверху висит kswapd0 с 100% CPU, это почти всегда означает одно: ядро отчаянно пытается освободить память (memory reclaim), но делает это слишком часто и слишком дорого. В результате растут задержки, процессы залипают, иногда прилетает OOM killer — и сервисы падают.
Ниже — практичный разбор: что именно делает kswapd0, чем опасен direct reclaim, как быстро подтвердить гипотезу через vmstat и pressure stall information (PSI), как выйти на конкретный cgroup/контейнер по памяти и какие действия реально помогают.
Что такое kswapd0 и почему он «жрёт» CPU
kswapd0 — это фоновый поток ядра (kernel thread), который запускает reclaim: освобождение страниц памяти. Он старается делать это заранее, чтобы обычные процессы не упирались в нехватку памяти в момент аллокации.
Упрощённо: когда свободной памяти становится мало, ядро может:
- освобождать page cache (и при необходимости инициировать writeback «грязных» страниц);
- вытеснять анонимную память в swap (если swap есть и это разрешено политиками);
- сжимать/освобождать slab-объекты и другие кэши через shrinkers;
- в крайнем случае — запускать механизм OOM и убивать процессы.
Высокий CPU у kswapd0 часто говорит не о том, что «CPU слабый», а о том, что система вошла в режим постоянной уборки памяти. Это состояние называют memory pressure или reclaim thrashing.
Фоновый reclaim vs direct reclaim: где больнее
Есть два режима reclaim:
- Background reclaim — когда
kswapd0в фоне пытается вернуть память, пока приложения продолжают работать. - Direct reclaim — когда конкретный процесс, пытаясь выделить память, вынужден сам идти «убираться». Он блокируется на reclaim, и вы видите лавинообразный рост задержек.
Ключевой симптом direct reclaim: CPU может быть не забит «полезной» работой, но приложение отвечает медленно, потому что его потоки реально стоят и ждут освобождения памяти.
Почему это важно: с kswapd0 можно некоторое время «жить» (хотя и плохо), а вот массовый direct reclaim обычно сразу бьёт по latency и вызывает таймауты в БД, PHP-FPM, JVM и т.д.

Быстрая диагностика: подтвердить memory reclaim за 2–3 минуты
1) vmstat: смотрим своп, run queue и признаки блокировок
Начните с:
vmstat 1
На что смотреть:
r— очередь на CPU. Еслиrумеренно, а тормоза сильные, часто виноваты ожидания памяти/IO.si/so— swap in/out. Постоянно ненулевые значения — признак активного свопинга (при задержках почти всегда подозрительно).wa— iowait. При активном writeback/pageout может расти.us/sy— системное время (sy) часто растёт при интенсивном reclaim.
Если so стабильно ненулевой и параллельно сервисы тормозят — вы почти наверняка в сценарии, где reclaim + swap/IO дают хвосты задержек.
2) PSI: pressure stall information показывает, «сколько времени мы реально стояли»
PSI — быстрый индикатор того, что система теряет время из-за давления на ресурс. Для памяти:
cat /proc/pressure/memory
Вы увидите some и full с метриками avg10, avg60, avg300. Интерпретация практичная:
some— часть задач испытывала stall по памяти;full— в какой-то момент все runnable-задачи упирались в память (для latency это очень больно).
Если memory full avg10 заметно больше нуля во время инцидента — это сильный сигнал, что именно память/reclaim «держат» систему, а не CPU.
3) dmesg: был ли OOM и кто пострадал
dmesg -T | grep -E "Out of memory|Killed process|oom-kill"
Если срабатывал OOM killer, важно понять: это был общий OOM системы или OOM внутри cgroup. В логе часто видно, что именно убили и по какой причине.
4) free и slab: куда ушла память
free -m
Смотрите не только «free», а картину целиком: available, объём cache/buffers.
Дополнительно:
grep -E "Slab:|SReclaimable:|SUnreclaim:" /proc/meminfo
Если SUnreclaim растёт и занимает значимый процент RAM — reclaim будет тяжёлым, а kswapd0 может крутиться на попытках освободить то, что почти не освобождается.
Где искать корень: типовые причины kswapd0 100% CPU
Причина 1: памяти реально не хватает, и начинается thrashing
Классика: рабочий набор приложений больше RAM, swap либо медленный, либо его нет, и система постоянно гоняет reclaim.
Признаки:
- высокие PSI по памяти;
- рост
si/soвvmstat(если swap включён); - скачки latency и таймауты.
Причина 2: direct reclaim из-за аллокаций в горячем пути
Некоторые нагрузки делают много аллокаций в критичных потоках: веб-воркеры, GC в JVM, компиляции, большие сортировки, массовые fork/exec. При этом «CPU занят» может означать «CPU потрачен на reclaim», а не на полезную работу.
Если вы тюните веб-стек, отдельно полезно понимать, что кэш и буферизация на уровне приложения могут резко менять рабочий набор. В тему кэширования пригодится материал про выбор Memcached/Redis для кэша в PHP — часто именно кэш становится главным потребителем RAM.
Причина 3: cgroup memory лимиты (контейнеры) и локальный OOM
В контейнерных средах (Docker, Kubernetes, systemd slices) бывает так: хост «ещё жив», но конкретный cgroup упирается в лимит. Тогда начинаются reclaim и/или OOM внутри cgroup, а kswapd0 хоста показывает нагрузку из-за общего давления.
Быстрые проверки для systemd/cgroup v2:
cat /sys/fs/cgroup/memory.current
cat /sys/fs/cgroup/memory.max
Если вы подозреваете конкретный сервис systemd:
systemctl status your-service
Для просмотра потребления по cgroup часто удобно:
systemd-cgtop
Причина 4: swap есть, но он «вредит» (медленный диск, лишний swappiness, шторм по pageout)
Swap сам по себе не зло: он может сгладить пики и удержать систему от мгновенного OOM. Но если swap на медленном диске, а RAM мало, система начинает активно пейджить, увеличивая wa и задержки. Тогда reclaim превращается в бесконечную попытку выгрызть память через дорогие IO-операции.
Посмотрите swap устройства:
swapon --show
И общую картину:
cat /proc/swaps
Причина 5: непропорциональный page cache или много «грязных» страниц
Иногда память «не утекла», а ушла в кэши/буферы, но освобождается слишком медленно из-за writeback. Тогда kswapd0 активно работает, но упирается в необходимость сначала сбросить данные на диск.
В таком случае полезно посмотреть:
grep -E "Dirty:|Writeback:" /proc/meminfo
Как найти виновника: процесс, память и cgroup
Топ процессов по RSS (быстро, но грубо)
ps -eo pid,ppid,comm,rss,%mem --sort=-rss | head -n 20
Это не показывает shared memory идеально, но для первичного поиска «кто съел RAM» обычно хватает.
Смотрим, кто вызывает reclaim чаще всего (perf)
Когда нужно понять, почему kswapd0 грузит CPU, помогает perf:
perf top -g
Если в стеке много функций reclaim (сканирование LRU, shrinkers), это подтверждает сценарий reclaim thrashing.
Если контейнеры: разложить по cgroup memory
Для cgroup v2 практичный путь — пройтись по дереву и найти, где пиковое потребление. На больших хостах делайте это аккуратно (может быть шумно), но как «разовая диагностика» работает:
find /sys/fs/cgroup -maxdepth 3 -name memory.current -print -exec cat {} \;
Если среда запрещает такой обход или дерево огромное, используйте systemd-cgtop или метрики оркестратора.

Что делать: план стабилизации и профилактики
Шаг 1: остановить деградацию (быстрые действия)
- Снизить нагрузку: временно уменьшить параллелизм воркеров (PHP-FPM, gunicorn workers, очереди), отключить тяжёлые батчи (бэкапы, индексации).
- Проверить, не упёрлись ли в лимит cgroup: если лимит слишком низкий — либо поднимайте, либо уменьшайте рабочий набор (кэш, буферы, параллелизм).
- Оценить роль swap: если swap медленный и активно используется, чаще безопаснее сначала уменьшить давление (параллелизм/кэш), чем «рубить swap» на живом проде.
Важно: отключение swap может «вылечить» тормоза на тесте, но на проде легко приводит к быстрому OOM и падению процессов. Сначала оцените, есть ли запас по RAM и что показывает PSI после снижения нагрузки.
Шаг 2: привести память в соответствие рабочему набору
Самая надёжная мера — чтобы рабочий набор помещался в RAM. Если сервисам действительно нужно больше памяти, никакие тюнинги не заменят достаточный объём RAM. В таких случаях проще и дешевле по времени сразу переехать на более ёмкий тариф VDS, чем неделями ловить трешинг под пиками.
Если память «раздувает» конфигурация:
- уменьшайте число воркеров и размеры кэшей (приложение, БД, JVM heap);
- смотрите на пики: часто проблема в фоновых задачах или батчах;
- для контейнеров держите лимиты реалистичными: «впритык» почти гарантирует reclaim/OOM под пиками.
Шаг 3: аккуратные sysctl-настройки (когда понимаете эффект)
Некоторые параметры ядра влияют на reclaim и swap. Универсальных значений «для всех» нет: всё зависит от типа нагрузки, наличия swap, скорости диска, профиля БД.
Что обычно проверяют в контексте подобных инцидентов:
vm.swappiness— склонность уходить в swap;vm.vfs_cache_pressure— агрессивность reclaim кэшей inode/dentry;vm.dirty_ratio,vm.dirty_background_ratio(или байтовые аналоги) — сколько «грязных» данных держать до активного сброса.
Снять текущие значения можно так:
sysctl vm.swappiness
sysctl vm.vfs_cache_pressure
sysctl vm.dirty_ratio
sysctl vm.dirty_background_ratio
Менять — только после того, как вы подтвердили узкое место метриками (PSI, vmstat, iostat) и понимаете, что именно хотите улучшить: latency, writeback или уменьшение pageout.
Шаг 4: сделать OOM предсказуемым, а не случайным
Когда память заканчивается, OOM killer всё равно должен выбрать жертву. Важно, чтобы это была «правильная» жертва, а не, например, база данных или ingress.
- Настройте лимиты памяти для сервисов (systemd/cgroup) так, чтобы «падающий» компонент не уносил весь узел.
- Разделяйте критичные и некритичные сервисы по cgroup/slices.
- Следите за PSI и трендами потребления, чтобы не жить в режиме постоянного reclaim.
Шпаргалка: как выглядит «здорово» и как выглядит «плохо»
Плохо (типичный инцидент)
kswapd0стабильно в топе по CPU;vmstat: естьso, растётwa,syзаметный;- PSI memory:
full avg10выше нуля,someощутимый; - таймауты приложений, рост p95/p99.
Здорово (после исправлений)
kswapd0не доминирует по CPU;- PSI memory близок к нулю большую часть времени;
- swap (если включён) используется умеренно и без постоянного pageout;
- пики нагрузки не приводят к лавинообразному росту задержек.
Частый вопрос: почему «памяти свободно мало», но всё должно быть нормально?
Linux активно использует RAM под page cache — это нормально. Важнее не «free», а available и поведение под нагрузкой. Проблема начинается, когда доступной памяти недостаточно для рабочего набора, и система вынуждена постоянно очищать страницы, вызывая memory reclaim и особенно direct reclaim.
Мини-плейбук для дежурного: что выполнить и что записать в постмортем
- Снимите
vmstat 1на 1–2 минуты и сохраните вывод. - Снимите PSI:
cat /proc/pressure/memory(и при желании CPU/IO). - Снимите топ по памяти:
psпо RSS, и при контейнерах —systemd-cgtop. - Проверьте OOM-события в
dmesg. - Зафиксируйте текущие
vm.*изsysctl, которые могли влиять на reclaim.
Эти данные почти всегда позволяют отличить «реально не хватает RAM» от «проблема в лимитах cgroup», «writeback/диск» или «аномально раздутый кэш/утечка».
Вывод
kswapd0 на 100% CPU — это симптом, а не диагноз. Диагноз строится по трём опорам: vmstat (swap/очереди/ожидания), PSI (реальная потеря времени на memory pressure) и разрез по процессам/cgroup. После этого решения становятся проще: уменьшить рабочий набор, исправить лимиты, аккуратно настроить swap и writeback и сделать поведение при OOM предсказуемым.


