Тонкая настройка swappiness и zswap в Linux: защита БД и Web от OOM и просадок I/O

Гайд по настройке swappiness и zswap в Linux для серверов БД и Web. Защита от OOM, оптимизация памяти и предотвращение деградации дискового I/O.

2026.07.08                  


Тонкая настройка swappiness и zswap в Linux: защита БД и Web от OOM и просадок I/OТонкая настройка swappiness и zswap в Linux: защита БД и Web от OOM и просадок I/O Настройка сервера, на котором одновременно работают База Данных (БД) и Web-приложения — это всегда поиск баланса. БД крайне чувствительны к задержкам дисковой подсистемы (I/O), а Web-серверы любят держать много данных в кэше. Стандартные настройки Linux здесь не подходят: дефолтный swappiness=60 заставит сервер активно сбрасывать страницы на диск, что убьет производительность БД, а при пиковых нагрузках OOM-killer может «убить» именно процесс БД.

Ниже представлен подробный гайд по тонкой настройке подсистемы памяти с использованием zswap и swappiness.


Часть 1. Фундамент: Почему именно Zswap и низкий Swappiness?

1. vm.swappiness:

Определяет, насколько агрессивно ядро будет сбрасывать неиспользуемые страницы памяти (anonymous memory) в swap. Для БД мы снизим его до 1, чтобы ядро держало данные в RAM до последнего.


2. zswap:

Это не замена swap-разделу, а легковесный сжатый кэш в RAM для swap-страниц. Когда ядро решает, что страницу нужно выгрузить в swap, zswap сначала сжимает её и кладет в специальную зону в RAM.

Результат:

Вместо медленного диска мы тратим микросекунды CPU на сжатие. Диск не используется, I/O не деградирует. На диск страница попадет только если сжатый кэш zswap переполнится.


Часть 2. Настройка vm.swappiness

Для смешанной нагрузки (БД + Web) значение 60 категорически не подходит. Значение 0 в старых ядрах отключало swap полностью (что плохо, так как ломает логику OOM-killer), поэтому мы ставим 1. Это скажет ядру: «Используй swap только в случае экстремальной нехватки памяти».


Применение на лету (без перезагрузки):

sysctl -w vm.swappiness=1

Сохранение навсегда:

Добавьте в /etc/sysctl.conf (или создайте файл /etc/sysctl.d/99-memory-tuning.conf):

vm.swappiness = 1

Часть 3. Включение и тонкая настройка Zswap

Требование:

Ядро Linux 5.20 или новее (для поддержки алгоритма zstd. Если ядро старое, используйте lz4).


Важно:

Zswap требует, чтобы в системе был настроен классический swap (файл или раздел). Zswap — это прослойка перед ним.


1. Проверка поддержки ядром

Убедитесь, что модуль загружен:

grep -i zswap /boot/config-$(uname -r)

Должно быть CONFIG_ZSWAP=y.


2. Настройка параметров Zswap

Лучший способ гарантировать, что параметры zswap применятся при загрузке — передать их через параметры ядра (GRUB).


Откройте /etc/default/grub и найдите строку GRUB_CMDLINE_LINUX (или GRUB_CMDLINE_LINUX_DEFAULT). Добавьте в неё следующие параметры:

zswap.enabled=1 zswap.compressor=zstd zswap.zpool=zsmalloc zswap.max_pool_percent=20

Разбор параметров:

  • enabled=1 — включает zswap.
  • compressor=zstd — алгоритм сжатия. zstd дает лучшее соотношение скорости и степени сжатия на современных CPU.
  • zpool=zsmalloc — аллокатор памяти для сжатых страниц. zsmalloc отлично работает с разнородными данными БД и Web.
  • max_pool_percent=20Критически важный параметр! Ограничивает размер пула zswap до 20% от общего объема RAM. Это гарантирует, что zswap не «съест» всю память, оставив место для самих БД и Web-кэша.

3. Применение настроек GRUB

# Для Debian/Ubuntu:
update-grub

# Для CentOS/RHEL/Alma/Rocky:
grub2-mkconfig -o /boot/grub2/grub.cfg
# (или /boot/efi/EFI/.../grub.cfg в зависимости отUEFI)

Потребуется перезагрузка сервера, чтобы параметры ядра вступили в силу.


Часть 4. Предотвращение деградации дисковой подсистемы (I/O)

Сами по себе swappiness и zswap не решат проблему, если БД начнет генерировать огромные объемы «грязных» страниц (dirty pages), которые ядро попытается сбросить на диск одним залпом. Это вызовет I/O spike (всплеск) и фризы.


Добавьте в /etc/sysctl.d/99-memory-tuning.conf следующие параметры:

# Снижаем порог грязных страниц, чтобы ядро начинало сбрасывать их на диск плавно, а не одним ударом.
# Дефолт: 20 и 10. Для БД лучше 5 и 2 (или 10 и 3 на очень быстрых NVMe).
vm.dirty_background_ratio = 3
vm.dirty_ratio = 10

# Уменьшаем давление на кэш dentries и inodes. 
# Web-серверу и БД важно держать структуру файлов в памяти.
# Дефолт 100. Ставим 50, чтобы кэш жил дольше.
vm.vfs_cache_pressure = 50

# Запрещаем ядру чрезмерно увлекаться compaction (уплотнением памяти), 
# что может вызывать лаги CPU на больших объемах RAM.
vm.compact_unevictable_allowed = 0

Применить без перезагрузки: sysctl -p /etc/sysctl.d/99-memory-tuning.conf


Часть 5. Защита от OOM (OOM-Killer Tuning)

Даже с идеальной настройкой памяти, при жестком пике (например, бэкап + тяжелый запрос + пик Web-трафика) может сработать OOM-killer. По умолчанию он убивает тот процесс, который потребляет больше всего памяти. Нам нужно защитить БД.


Для PostgreSQL:

Нужно настроить oom_score_adj для процесса postgres.

  1. Откройте postgresql.conf.
  2. Найдите/добавьте параметр (в новых версиях PG) или настройте через systemd.

Через systemd (предпочтительный способ):

systemctl edit postgresql.service

Добавьте:

[Service]
OOMScoreAdjust=-900

(Значение от -1000 до 1000. -1000 полностью запрещает убивать процесс, -900 делает его крайне непривлекательным для OOM-killer).


Для MySQL/MariaDB:

Аналогично через systemd:

systemctl edit mariadb.service # или mysqld.service
[Service]
OOMScoreAdjust=-900

После этого перезапустите службы БД: systemctl restart postgresql (или mariadb).


Часть 6. Мониторинг и проверка

После перезагрузки сервера убедитесь, что всё применилось.

1. Проверка swappiness и dirty ratios:

sysctl vm.swappiness vm.dirty_ratio vm.dirty_background_ratio vm.vfs_cache_pressure

2. Проверка работы Zswap:

Посмотрите статистику zswap (покажет, сколько страниц сжато и сколько ушло на реальный диск):

cat /sys/kernel/debug/zswap/*

На что смотреть:

  • pool_total_size — сколько RAM сейчас занимает сжатый кэш (не должен превышать 20% от RAM).
  • stored_pages — количество сжатых страниц.
  • written_back_pagesсамое важное! Если это число растет в простое или при средних нагрузках — значит, пул zswap переполняется и данные уходят на медленный диск. Если нужно, увеличьте zswap.max_pool_percent до 25-30.

3. Проверка защиты от OOM:

cat /proc/$(pidof postgres)/oom_score_adj
# Должно вывести -900

Важно:

1. Swappiness = 1:

Мы запретили ядру лезть на диск просто так.

2. Zswap (zstd, 20% RAM):

Мы создали буфер в оперативной памяти. Если память все же начнет заканчиваться, страницы сожмутся в RAM, а не пойдут на диск. Диск не страдает, I/O не проседает.

3. Dirty ratios (3/10):

Мы заставили ядро сбрасывать изменения БД на диск плавно, избегая I/O-фризов.

4. OOMScoreAdjust = -900:

Мы защитили процесс БД от случайного убийства ядром в пользу менее важных Web-процессов.


Мы делимся этой технической информацией, чтобы помочь вам в решении задач — используйте её с пониманием. Статья носит рекомендательный характер, поэтому, пожалуйста, применяйте описанные методы осмотрительно.


Статью подготовил: Денис Аверко @Nymexis г. Омск

Комментарии

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