Лучшие практики настройки подкачки и поведения кэша в Linux

Тщательная настройка swappiness и VFS-кэша в Linux с примерами рабочих нагрузок, командами sysctl и шагами проверки.

Лучшие практики настройки подкачки и поведения кэша в Linux

Linux использует свободную оперативную память. Это удивляет людей, когда они впервые видят сервер с очень малым количеством «свободной» памяти в free -h. Большая часть этой памяти может быть кэшем страниц, dentries и inode-кэшем, а не утечкой. Сложность заключается в том, чтобы понять, когда ядро эффективно использует ОЗУ, а когда освобождение памяти начинает вредить вашим приложениям.

Два параметра sysctl часто упоминаются при настройке памяти Linux: vm.swappiness и vm.vfs_cache_pressure. Они полезны, но не являются волшебными переключателями производительности. Неправильное значение может скрыть реальную проблему или перенести нагрузку с одной рабочей нагрузки на другую.

Понимание параметров управления памятью Linux

Linux использует эвристику для принятия решения о том, какие страницы памяти освобождать, когда системе требуется больше свободной ОЗУ. Две основные области, контролируемые параметрами ядра, — это подкачка (перемещение неактивных страниц памяти на диск) и кэширование (хранение метаданных файловой системы и данных в ОЗУ).

1. vm.swappiness

vm.swappiness определяет склонность ядра к перемещению процессов из физической памяти в пространство подкачки на диске. Это значение от 0 до 100.

  • Более высокое значение (например, 60, распространенное значение по умолчанию): Ядро более склонно освобождать анонимную память и использовать подкачку как часть обычного управления памятью. Это может сохранить кэш страниц, но также может навредить чувствительным к задержкам сервисам, если активные страницы будут вытеснены.
  • Низкое значение (например, 10 или меньше): Ядро предпочитает освобождать память из кэша страниц до того, как начнет вытеснять процессы в подкачку. Это дольше удерживает работающие приложения в ОЗУ, улучшая отзывчивость, но потенциально снижая производительность дискового ввода-вывода, если системе постоянно приходится сбрасывать страницы кэша.
  • Значение 0: Ядро избегает подкачки настолько, насколько это возможно, но это не отключает подкачку. Если вам нужно отключить подкачку, используйте swapoff и сначала оцените риск нехватки памяти (OOM).

Практическое применение vm.swappiness

Оптимальная настройка сильно зависит от рабочей нагрузки:

Тип рабочей нагрузки Рекомендуемый диапазон swappiness Обоснование
Серверы баз данных, высокопроизводительные вычисления (HPC) 1 - 10 Часто хорошая отправная точка, когда задержка подкачки хуже, чем сброс кэша. Проверьте с помощью метрик реальной рабочей нагрузки.
Серверы общего назначения, рабочие станции 30 - 60 Обычно разумно, если у вас нет доказательств, что поведение подкачки вам вредит.
Системы с интенсивным файловым обменом или кэшированием 60 или выше в некоторых случаях Может сохранить кэш страниц, но имеет смысл только в том случае, если периодическая подкачка приемлема для рабочей нагрузки.

Как проверить текущее значение:

cat /proc/sys/vm/swappiness

Как временно изменить значение (до перезагрузки):

Чтобы установить swappiness на 10:

sudo sysctl vm.swappiness=10

Как изменить значение навсегда:

Отредактируйте файл /etc/sysctl.conf и добавьте или измените строку:

# /etc/sysctl.conf
vm.swappiness = 10

После сохранения примените изменения без перезагрузки с помощью:

sudo sysctl -p

Для баз данных с интенсивным использованием памяти 1-10 — распространенная отправная точка. Не воспринимайте это как правило. База данных, у которой уже есть собственный буферный кэш, например PostgreSQL или MySQL/InnoDB, обычно выигрывает от избегания подкачки. Файловый сервер может предпочесть больший кэш страниц. Небольшая виртуальная машина с недостаточным объемом ОЗУ будет страдать независимо от того, какое число вы выберете.

2. vfs_cache_pressure

vfs_cache_pressure управляет тем, насколько агрессивно ядро освобождает память, используемую для метаданных каталогов и inode (VFS-кэш).

  • Это значение варьируется от 0 до 1000.
  • Значение по умолчанию обычно равно 100.

При значении 100 ядро балансирует освобождение памяти VFS-кэша с освобождением памяти, используемой кэшем страниц (данные на диске). Значение 100 означает, что при нехватке памяти ядро пытается освободить 1 часть памяти inode/dentry-кэша на каждую 1 часть памяти кэша страниц.

Настройка vfs_cache_pressure

  • Увеличение значения (например, > 100): Делает ядро более агрессивным в освобождении памяти VFS-кэша. Это быстрее освобождает ОЗУ, но может привести к замедлению последующих операций поиска в файловой системе, так как метаданные нужно будет снова читать с диска.
  • Уменьшение значения (например, < 100): Делает ядро более консервативным в освобождении VFS-кэша. Это дольше удерживает информацию о каталогах и inode в памяти, ускоряя повторяющиеся операции файловой системы.

Когда уменьшать vfs_cache_pressure:

Если ваша система часто обращается к одним и тем же большим структурам каталогов (распространено в сложных приложениях, оркестрации контейнеров или определенных сетевых конфигурациях), установка этого значения ниже (например, 50) может повысить производительность, сохраняя метаданные в ОЗУ.

Когда увеличивать vfs_cache_pressure:

Если ваша система страдает от общей нехватки памяти, и вы хотите, чтобы ядро быстро освобождало любую неиспользуемую память, вы можете повысить это значение, хотя это менее распространено, чем его понижение.

Как проверить текущее значение:

cat /proc/sys/vm/vfs_cache_pressure

Как изменить значение навсегда:

Отредактируйте /etc/sysctl.conf:

# /etc/sysctl.conf
vfs_cache_pressure = 50

Примените изменения с помощью sudo sysctl -p.

Предупреждение: Очень низкие значения vfs_cache_pressure могут заставить ядро удерживать кэш каталогов и inode дольше, чем вы ожидаете. Это может помочь рабочим нагрузкам с интенсивным использованием метаданных, но также может усугубить нехватку памяти для приложений. Избегайте экстремальных значений, если вы не измерили эффект.

Комплексные сценарии настройки

Выбор правильной комбинации этих параметров оптимизирует компромисс между стабильностью приложений и кэшированием файловой системы.

Сценарий 1: Сервер базы данных (приоритет памяти)

Цель: Максимизировать резидентность памяти приложений; минимизировать подкачку любой ценой.

  • vm.swappiness = 5
  • vfs_cache_pressure = 50 (Сохранять данные каталогов в кэше в некоторой степени, но отдавать приоритет памяти приложений над VFS-метаданными, если ОЗУ становится мало).

Прежде чем что-либо менять, проверьте, использует ли база данных подкачку:

free -h
vmstat 1
grep -E 'pswpin|pswpout' /proc/vmstat

Если счетчики подкачки (swap-in и swap-out) растут во время всплесков задержки запросов, снижение swappiness может помочь. Если подкачка не используется, а база данных работает медленно, swappiness не является вашей проблемой. Вместо этого посмотрите на планы запросов, коэффициент попадания в буфер, контрольные точки, задержку диска и давление соединений.

Сценарий 2: Сервер с высокой нагрузкой на дисковый ввод-вывод (приоритет кэширования)

Цель: Максимизировать производительность диска, сохраняя часто запрашиваемые данные файлов в кэше страниц.

  • vm.swappiness = 80 (Разрешает подкачку раньше, чтобы освободить ОЗУ для расширения дискового кэша).
  • vfs_cache_pressure = 100 (Стандартный баланс между inode-кэшем и кэшем страниц).

Это сценарий, в котором люди чаще всего чрезмерно настраивают параметры. Если сервер в основном читает одни и те же файлы повторно, кэш страниц важен. Но если система начинает вытеснять активные рабочие процессы в подкачку для сохранения кэша, пользователи могут наблюдать худшую задержку, даже если кэш файловой системы выглядит здоровым. Следите за временем отклика приложений, а не только за размером кэша.

Сценарий 3: Хост виртуализации или система общего назначения

Цель: Стабильная производительность для нескольких рабочих нагрузок.

  • vm.swappiness = 30 (Умеренная настройка, которая предпочитает удерживать активные виртуальные машины/процессы в ОЗУ немного дольше, чем значение по умолчанию 60, но все же допускает контролируемую подкачку).
  • vfs_cache_pressure = 100 (Значение по умолчанию часто достаточно).

Хостам виртуализации требуется дополнительная осторожность, потому что поведение памяти гостевых систем может ввести в заблуждение настройку хоста. Баллонирование, перераспределение и гостевая подкачка могут взаимодействовать. Хост, который активно вытесняет память гостевых систем, может создавать болезненную задержку внутри виртуальных машин, даже если каждая гостевая система считает свою собственную нагрузку нормальной.

Более безопасный рабочий процесс настройки

Не начинайте с редактирования /etc/sysctl.conf. Начните с доказательства того, что настройка актуальна.

  1. Зафиксируйте базовые показатели во время нормальной нагрузки:

    free -h
    vmstat 1 10
    cat /proc/sys/vm/swappiness
    cat /proc/sys/vm/vfs_cache_pressure
    
  2. Зафиксируйте те же данные в период замедления. Добавьте информацию о памяти на уровне процессов:

    ps -eo pid,comm,rss,vsz,%mem --sort=-rss | head -20
    
  3. Измените одно значение временно:

    sudo sysctl vm.swappiness=10
    
  4. Запустите рабочую нагрузку на достаточно долгое время, чтобы наблюдать поведение. Ищите снижение активности подкачки, лучшую задержку приложений и отсутствие нового замедления файловой системы.

  5. Делайте значение постоянным только после того, как оно выдержит реалистичный тестовый период.

В системах, использующих /etc/sysctl.d/, часто чище использовать отдельный небольшой файл, чем добавлять в /etc/sysctl.conf:

sudo tee /etc/sysctl.d/90-memory-tuning.conf >/dev/null <<'EOF'
vm.swappiness = 10
vm.vfs_cache_pressure = 100
EOF

sudo sysctl --system

Если ваша система управления конфигурацией управляет настройками sysctl, внесите изменения туда. Ручные правки sysctl на одном сервере легко забыть и трудно воспроизвести.

Чтение free -h без паники

Типичный вывод free -h может показывать небольшое число в столбце free и большое число в столбце buff/cache. Это нормально. Linux хранит недавно использованные данные файлов в памяти, потому что неиспользуемая ОЗУ никому не помогает.

Сосредоточьтесь на available, использовании подкачки и на том, происходит ли активность подкачки сейчас. Сервер может иметь выделенную подкачку от прошлого всплеска памяти, но без текущего обмена подкачки. Это менее срочно, чем сервер, который постоянно выполняет подкачку (swap in/out).

Используйте:

vmstat 1

Если si и so остаются около нуля при нормальной нагрузке, подкачка не является активным источником задержки в данный момент. Если они остаются ненулевыми, в то время как приложения зависают, нехватка памяти является серьезным подозреваемым.

Когда не нужно настраивать эти параметры

Есть несколько случаев, когда изменение swappiness или cache pressure является неправильным первым шагом.

Если на сервере не настроена подкачка, vm.swappiness имеет мало практического эффекта. Вы все еще можете настроить его для согласованности политики, но это не решит проблему нехватки памяти само по себе.

Если подкачка существует только как крошечный аварийный раздел, настройка также имеет ограниченные возможности для помощи. Ядро может решить, когда использовать подкачку, но оно не может превратить несколько сотен мегабайт аварийного пространства в настоящий уровень памяти. В такой конфигурации сосредоточьтесь на риске OOM и ограничениях сервиса.

Если у процесса есть реальная утечка памяти, снижение swappiness только отсрочивает боль. Утечка будет продолжать расти. Перезапуск сервиса может временно восстановить емкость, но долговременное решение находится на уровне приложения: исправить утечку, ограничить память, уменьшить параллелизм или изменить рабочую нагрузку.

Если диск медленный из-за неисправного диска, ограничения хранилища или насыщенного облачного тома, настройка памяти может уменьшить некоторые чтения, но не исправит неисправность хранилища. Проверьте iostat, журналы ядра, метрики облачных томов и состояние SMART/NVMe.

Если рабочий набор данных больше, чем ОЗУ, не существует идеального значения sysctl. Вам нужно больше памяти, меньше параллелизма, меньшие кэши, другое расположение данных или разделение рабочей нагрузки.

Заметки о контейнерах и Kubernetes

Настройка памяти становится сложнее в контейнерах. Контейнер может достичь своего лимита памяти cgroup, даже если на хосте есть свободная ОЗУ. Настройка swappiness хоста все еще имеет значение, но непосредственным симптомом может быть OOM kill внутри пода или контейнера.

Проверьте cgroup и сигналы оркестратора:

dmesg -T | grep -i 'killed process'
docker stats
kubectl describe pod <имя-пода>

Для Kubernetes изменение sysctl на уровне узла должно быть частью конфигурации пула узлов, а не одноразовой сессией в оболочке. Также помните, что некоторые sysctl являются пространственно-изолированными (namespaced), а некоторые — на уровне узла. vm.swappiness и vm.vfs_cache_pressure являются настройками уровня хоста в типичных системах Linux, поэтому их изменение влияет на каждую рабочую нагрузку на этом узле.


Мониторинг и проверка

После применения изменений непрерывный мониторинг имеет решающее значение для проверки влияния. Используйте такие инструменты, как free, vmstat и панели мониторинга производительности системы.

Использование vmstat:

Отслеживайте столбцы si (подкачка в) и so (подкачка из). Здоровая система с низким swappiness должна показывать низкие или нулевые значения si и so при нормальной нагрузке.

vmstat 5 10

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 123456 102400 5123456    0    0     0     5   40   70  1  1 98  0  0

Если значения so остаются высокими после снижения swappiness, рабочая нагрузка, вероятно, требует больше доступной памяти или меньшего спроса на память. Больше ОЗУ — это один из ответов, но не единственный. Вы также можете уменьшить количество рабочих процессов, сократить кэши приложений, настроить память базы данных, исправить утечки или разделить сервисы между хостами.

Относитесь к vm.swappiness и vm.vfs_cache_pressure как к предпочтениям рабочей нагрузки, а не универсальным улучшениям. Практический путь скучен, но надежен: измерьте текущее поведение подкачки и освобождения памяти, измените одну настройку, протестируйте под реальной нагрузкой и сохраните изменение только в том случае, если поведение приложения улучшится.