В Linux подсистема управления памятью устроена сложнее, чем популярная схема «есть RAM, есть swap, значит надо просто поставить vm.swappiness=1». На практике поведение сервера определяется сразу несколькими механизмами: вытеснением анонимной памяти, удержанием page cache, скоростью фоновой записи грязных страниц на диск и агрессивностью очистки VFS-кэшей. Поэтому параметры vm.swappiness, vm.vfs_cache_pressure, vm.dirty_ratio, vm.dirty_background_ratio, а также vm.dirty_bytes и vm.dirty_background_bytes нужно рассматривать вместе.
Если говорить по-простому, ядро постоянно балансирует между тремя задачами: оставить больше памяти приложениям, сохранить полезный файловый кэш и не допустить лавины записи на диск в неудобный момент. Ошибка настройки обычно проявляется не сразу. Сервер может выглядеть «нормально» по графикам RAM, а потом внезапно выдать скачок iowait, рост latency у PHP, Node.js, MySQL или PostgreSQL, либо начать активно свопиться на фоне бэкапа, логротации или импорта данных.
На VDS ситуация часто ещё интереснее: дисковая подсистема может быть очень быстрой, а может делиться с соседями; swap может быть локальным или отключённым; реальная цена ошибки — задержки сайта, очереди воркеров и таймауты БД. Поэтому тюнинг памяти в изоляции от диска и реальной нагрузки почти всегда даёт ложные выводы.
В этой статье разберём, что делают ключевые vm sysctl, как их смотреть, в какой последовательности менять и как не перепутать оптимизацию с самоуспокоением. Упор будет не на «магические значения», а на причинно-следственные связи и диагностику.
Сразу важная мысль: тюнинг памяти — это не способ компенсировать нехватку RAM. Если сервер стабильно упирается в память, параметры могут лишь изменить характер деградации. Иногда это полезно, но чудес не будет.
Что именно настраивают swappiness, vfs_cache_pressure и dirty_ratio
Чтобы понимать эффект параметров, полезно разделить память на несколько логических зон поведения. Есть анонимная память процессов: стек, heap, структуры рантайма, буферы приложений. Есть файловый кэш, или page cache, который ускоряет чтение файлов и повторный доступ к данным. Есть VFS-кэши — например, dentry и inode cache, помогающие быстрее работать с метаданными файловой системы. И есть грязные страницы — данные, уже изменённые в RAM, но ещё не записанные на диск.
vm.swappiness влияет на то, насколько охотно ядро будет вытеснять анонимную память в swap, сохраняя при этом файловый кэш. Это не переключатель «включить swap» или «запретить swap». Значение определяет склонность к обмену между удержанием page cache и высвобождением RAM через swap.
vm.vfs_cache_pressure задаёт, насколько агрессивно ядро будет reclaim'ить VFS-кэши. Если поставить слишком высоко, кэши метаданных будут быстро вымываться, и сервер с большим количеством мелких файлов начнёт чаще ходить на диск. Если слишком низко, ядро может слишком бережно держать dentry/inode cache, вытесняя что-то более полезное.
vm.dirty_background_ratio и vm.dirty_ratio управляют записью грязных страниц. Первый порог запускает фоновый writeback: ядро начинает сбрасывать dirty pages на диск заранее. Второй — жёстче: если грязных страниц стало слишком много, процесс, который пишет данные, может быть принудительно замедлен, пока запись не догонит накопившийся объём.
Параметры dirty_background_bytes и dirty_bytes делают то же самое, но в абсолютных байтах. Это часто удобнее на серверах с большим объёмом RAM, где процентные настройки превращаются в слишком крупные буферы записи. Например, 20% от 64 ГБ — это уже десятки гигабайт грязных страниц, что может закончиться неприятно даже на быстром SSD.
Почему стандартные советы вроде swappiness=1 работают не всегда
Самый живучий миф — «если это сервер, надо поставить swappiness=1 или даже 0». Логика понятна: никто не хочет, чтобы рабочая память приложения внезапно оказалась в swap. Но проблема в том, что swap — это не только аварийная зона, а часть стратегии управления памятью. Иногда умеренный swap позволяет сохранить page cache и сгладить пиковые нагрузки. Иногда, наоборот, активный swap создаёт хвост задержек, потому что приложение начинает трогать давно вытесненные страницы.
На веб-серверах с PHP-FPM, Python, Node.js или Java часто есть смесь долгоживущих и не очень активных процессов. Часть страниц памяти может использоваться редко. Если ядро совсем не хочет свопить, оно будет агрессивнее вычищать кэши. Это может ухудшить производительность файловых операций, статической раздачи, работы с пакетами, логами и даже с БД, если те завязаны на файловый кэш.
С другой стороны, слишком высокий swappiness на сервере с медленным диском или нестабильной задержкой хранилища может приводить к затяжным паузам. Именно поэтому правильный вопрос звучит не «какое значение модно сейчас», а «что сейчас ограничивает сервер: RAM, page cache, latency диска или writeback».
Если после снижения
swappinessграфик swap перестал расти, это ещё не означает улучшение. Возможно, сервер просто начал чаще вычищать page cache, и просадка переехала из swap в disk IO.

На системах, где важна скорость работы с файлами, полезно отдельно следить за тем, насколько приложение вообще выигрывает от кэшей. Например, для PHP-стека нередко оказывается важнее не «убить swap», а правильно разнести нагрузку между page cache, OPcache и внешним кэшем вроде Redis или Memcached. Об этом я отдельно писал в материале про выбор между Memcached и Redis для PHP-кэша.
Как смотреть текущие значения и состояние памяти
Перед любыми изменениями нужно снять базовую картину. Сами значения sysctl без наблюдения за поведением сервера мало о чём говорят. Начните с текущих параметров:
sysctl vm.swappiness vm.vfs_cache_pressure vm.dirty_ratio vm.dirty_background_ratio vm.dirty_bytes vm.dirty_background_bytes
Дальше посмотрите общую картину памяти:
free -h
vmstat 1
grep -E 'MemAvailable|Cached|Dirty|Writeback|SReclaimable|SwapTotal|SwapFree' /proc/meminfo
Для понимания давления на память полезны PSI-метрики:
cat /proc/pressure/memory
cat /proc/pressure/io
А для оценки реальной записи на диск и задержек:
iostat -xz 1
pidstat -d 1
На что смотреть в первую очередь:
- растёт ли swap постоянно или только во время пиков;
- есть ли высокий
si/soвvmstat, то есть реальный swap in/out прямо сейчас; - накапливаются ли
DirtyиWritebackв/proc/meminfo; - есть ли заметный
avg10иavg60по memory/io PSI; - не упирается ли диск в latency при фоне записи.
Если у вас небольшой сервер без сложного мониторинга, даже этих команд уже достаточно, чтобы не тюнить вслепую. Важно повторять замеры в проблемный момент: во время бэкапа, выкладки, индексации, импорта, пикового трафика.
Практика по swappiness: когда снижать, а когда не трогать
Для большинства веб-серверов разумный стартовый диапазон vm.swappiness — от 10 до 30. Это не универсальная истина, но хороший безопасный коридор. Значение около 60, которое часто встречается по умолчанию, на серверных нагрузках нередко оказывается слишком «дружелюбным» к swap. Значение 1 подходит не всегда и особенно рискованно на узких по RAM узлах, где page cache всё ещё важен.
Когда снижение swappiness обычно оправдано:
- на сервере есть swap, и вы видите ощутимые latency-скачки из-за swap in/out;
- приложения чувствительны к задержкам доступа к памяти;
- рабочий набор данных плохо помещается в RAM, и любое вытеснение анонимной памяти болезненно;
- диск под swap не отличается стабильной задержкой.
Когда не стоит бездумно ставить 1:
- сервер активно работает с файлами и выигрывает от большого page cache;
- на машине много редко используемых процессов, которые можно было бы мягко вытеснить;
- система начинает чаще упираться в очистку кэша и рост чтения с диска после снижения параметра;
- у вас нет наблюдаемой проблемы, а есть только желание «сделать по best practice».
Временное изменение для теста:
sysctl -w vm.swappiness=20
Постоянно на Debian и Ubuntu удобно задавать через отдельный файл:
printf 'vm.swappiness = 20
' > /etc/sysctl.d/90-vm-tuning.conf
sysctl --system
После этого следите не только за объёмом swap, но и за общим временем ответа приложений, PSI memory и частотой major page faults. Цель — не «убрать swap из графика», а уменьшить вред от memory pressure.
Как работает vfs_cache_pressure и где он реально заметен
vm.vfs_cache_pressure часто меняют реже, чем swappiness, но на некоторых типах нагрузки он влияет сильнее. Этот параметр регулирует давление на кэш метаданных файловой системы. Если сервер постоянно открывает множество файлов, работает с деревьями каталогов, логами, кешем пакетов, сессиями, статиками или CMS с большим количеством мелких файлов, удержание inode/dentry cache может быть очень полезным.
Типичное значение по умолчанию — 100. Снижение до 50 или 75 иногда помогает серверам, где метаданные файловой системы активно используются и быстро переиспользуются. Но слишком низкие значения могут сделать reclaim менее эффективным: VFS-кэши будут жить слишком долго, а давление перераспределится на другие области памяти.
Повышение параметра выше 100 бывает оправдано редко. Обычно это попытка насильно вычистить кэши при нехватке RAM, но эффект часто краткосрочный. Если памяти реально мало, проблема вернётся, только уже с дополнительными промахами кэша и ростом IO.
Практический ориентир такой:
100— нормальная базовая точка;50–75— можно тестировать на веб-серверах и файлово-нагруженных узлах;200+— только при чётком понимании, зачем вы так aggressively reclaim'ите VFS cache.
Проверить текущие slab-кэши можно так:
slabtop -o
grep -E 'SReclaimable|Slab' /proc/meminfo
Если после снижения vfs_cache_pressure уменьшается число обращений к диску на повторных операциях с файлами, а memory pressure не растёт — это хороший знак. Если же у сервера резко падает MemAvailable, а PSI по памяти ползёт вверх, значит, вы слишком щедро держите метаданные в RAM.
Dirty pages и writeback tuning: где рождаются фризы записи
Теперь к самой недооценённой части — writeback. Параметры dirty writeback особенно важны на серверах, где идут интенсивные записи: базы данных, очереди, кеши на диске, логи, ротации, бэкапы, распаковка архивов, CI-сборки. Суть механизма такая: процесс пишет данные не всегда прямо на диск. Сначала данные попадают в page cache и помечаются как dirty. Позже ядро сбрасывает их на накопитель.
Это ускоряет запись и сглаживает нагрузку, но только пока пороги настроены адекватно. Если dirty pages можно накопить слишком много, то в какой-то момент система получает большой хвост writeback. Тогда либо фоновые потоки начинают долго выгружать данные, либо сам пишущий процесс тормозится. Снаружи это выглядит как внезапный всплеск latency, особенно неприятный на виртуальных дисках.
vm.dirty_background_ratio задаёт порог старта фоновой записи. vm.dirty_ratio — порог, после которого процессам уже начинают «мешать писать слишком быстро». Если у вас значения по умолчанию и много RAM, эти пороги могут оказаться чрезмерно большими в абсолютных цифрах.
Поэтому на современных серверах я чаще предпочитаю не ratio, а bytes. Абсолютные значения делают поведение предсказуемее. Например, можно ограничить объём грязных данных до сотен мегабайт или пары гигабайт, а не до процентов от всей памяти, которые становятся опасно велики на больших конфигурациях.

Когда лучше ratio, а когда bytes
Используйте dirty_background_bytes и dirty_bytes, если:
- на сервере много RAM, и процентные значения дают слишком большой буфер записи;
- важна предсказуемая latency, а не максимальная пакетная пропускная способность;
- нагрузка сильно меняется, и вы хотите одинаковое поведение после апгрейда памяти.
Оставаться на ratio можно, если:
- сервер небольшой и объём RAM не будет резко меняться;
- нагрузка умеренная и нет проблем с writeback spikes;
- нужна простая базовая настройка без тонкой подгонки.
Важно: одновременно реально действует либо ratio-пара, либо bytes-пара. Если заданы байтовые лимиты, обычно ориентироваться нужно именно на них.
Практические стартовые значения
Для веб-сервера или универсального небольшого VDS часто безопаснее начать с консервативных значений, чтобы не допускать больших волн записи:
sysctl -w vm.dirty_background_bytes=134217728
sysctl -w vm.dirty_bytes=536870912
Это примерно 128 МБ и 512 МБ соответственно. Для более тяжёлой записи можно тестировать, например, 256 МБ и 1 ГБ. Но увеличивать стоит только после наблюдений за latency диска и общей пропускной способностью.
Если удобнее работать через ratio, осторожный стартовый вариант может выглядеть так:
sysctl -w vm.dirty_background_ratio=3
sysctl -w vm.dirty_ratio=10
Значения не универсальны, но они обычно лучше, чем слишком широкие пороги на серверах с десятками гигабайт памяти.
Готовые профили под типовые сценарии
Ниже не «канон», а отправные точки для теста.
Небольшой веб-сервер: Nginx, PHP-FPM, немного Redis, логи, бэкапы по ночам
Задача — не свопить активные воркеры и не накапливать слишком много dirty pages.
vm.swappiness = 10
vm.vfs_cache_pressure = 75
vm.dirty_background_bytes = 134217728
vm.dirty_bytes = 536870912
Такой профиль обычно даёт спокойное поведение, если RAM впритык не забита, а диск не слишком медленный.
Файлово-нагруженный узел: CMS, много мелких файлов, активный page cache
Здесь важен баланс в пользу кэшей метаданных и page cache. Если вы активно оптимизируете отдачу статики, дополнительно может пригодиться материал про настройку кеширования и выбора форматов в Nginx, потому что файловый профиль нагрузки напрямую влияет на полезность page cache.
vm.swappiness = 20
vm.vfs_cache_pressure = 50
vm.dirty_background_bytes = 268435456
vm.dirty_bytes = 1073741824
Но если после такого растёт memory PSI, параметр vfs_cache_pressure лучше вернуть ближе к 75–100.
Сервер с интенсивной записью логов, импортами и фоновыми задачами
Тут главная цель — уменьшить writeback spikes.
vm.swappiness = 10
vm.vfs_cache_pressure = 100
vm.dirty_background_bytes = 67108864
vm.dirty_bytes = 268435456
Да, пороги довольно низкие. Зато запись начинает уходить на диск раньше и меньшими порциями. Это часто помогает снизить хвостовые задержки.
Как вносить изменения безопасно
Главная ошибка — поменять сразу всё, потом заметить «стало вроде лучше» и оставить как есть. Правильнее идти короткими итерациями.
- Снимите базовые метрики до изменений: память, swap, PSI, IO latency, время ответа приложения.
- Меняйте одну группу параметров за раз: сначала
swappiness, потомvfs_cache_pressure, потом dirty writeback. - Тестируйте в типичном и пиковом сценарии, а не только на idle-сервере.
- Фиксируйте изменения в отдельном файле
/etc/sysctl.d/, чтобы их было легко откатить. - Сравнивайте не только «стало ли меньше swap», но и latency,
iowait, PSI, скорость ответа приложений.
Пример постоянной конфигурации:
printf 'vm.swappiness = 10
vm.vfs_cache_pressure = 75
vm.dirty_background_bytes = 134217728
vm.dirty_bytes = 536870912
' > /etc/sysctl.d/90-memory-writeback.conf
sysctl --system
После применения проверьте:
sysctl vm.swappiness vm.vfs_cache_pressure vm.dirty_background_bytes vm.dirty_bytes
Если вы только подбираете среду под такой профиль нагрузки, то для небольших сайтов и сервисов сравнить можно и виртуальный хостинг, и отдельный VDS: во втором случае у вас будет полный контроль над sysctl, swap и поведением writeback.
Типичные ошибки и антишаблоны
Первая ошибка — тюнинг без понимания профиля нагрузки. Сервер с PostgreSQL, сервер со статикой и CI runner — это три разные истории, даже если на них одинаковый объём RAM.
Вторая — борьба со следствием. Если приложение течёт по памяти, плодит воркеры или держит лишние кэши в userspace, swap tuning не решит проблему. Нужно сначала понять, куда уходит RAM.
Третья — слишком большие dirty-пороги на серверах с большим объёмом памяти. На графиках всё может быть красиво, пока не придёт момент сброса накопленного буфера на диск. Именно отсюда часто берутся внезапные фризы без видимой причины.
Четвёртая — судить о здоровье памяти только по команде free. Большой объём занятой RAM в Linux сам по себе не проблема. Важно, есть ли давление на память, swap activity, major faults и задержки IO.
Пятая — копировать чужие значения на прод без теста. Даже на двух похожих серверах результаты могут отличаться из-за дисковой подсистемы, версии ядра, файловой системы и характера приложения.
Как понять, что настройка удалась
Хороший результат — это не конкретное число в sysctl, а более предсказуемое поведение сервера. Обычно успех выглядит так: меньше хвостовых задержек под нагрузкой, меньше резких writeback-спайков, умеренный или стабильный swap без активного thrashing, отсутствие заметного memory PSI и более ровное время ответа приложений.
Если после изменений swap чуть-чуть используется, но сервер работает ровнее — это нормально. Если swap равен нулю, но приложение стало чаще упираться в диск и выросла latency — это плохая оптимизация. У Linux нет задачи порадовать администратора пустым swap-разделом; его задача — дать наилучший компромисс для реальной нагрузки.
Лучший тюнинг памяти — тот, который подтверждается метриками нагрузки, а не только эстетикой графиков.
Короткий вывод
vm.swappiness отвечает не за «включить или выключить swap», а за баланс между анонимной памятью и page cache. vm.vfs_cache_pressure влияет на сохранность кэшей метаданных файловой системы. vm.dirty_ratio, vm.dirty_background_ratio, vm.dirty_bytes и vm.dirty_background_bytes формируют характер writeback и могут либо сгладить запись, либо создать неприятные волны latency.
Если нужен практический старт без экстрима, я бы начал так: swappiness=10..20, vfs_cache_pressure=75..100, а dirty-пороги задавал бы в байтах и сравнительно консервативно. Дальше — только через наблюдение: vmstat, PSI, /proc/meminfo, iostat и метрики приложения.
И главное: тюнинг VM в Linux — это работа с компромиссами. Здесь редко бывает «самое правильное значение», но почти всегда можно найти настройку, которая лучше подходит именно вашему серверу и его реальной нагрузке.


