Тонкая настройка 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.
- Откройте
postgresql.conf. - Найдите/добавьте параметр (в новых версиях 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-процессов.
Мы делимся этой технической информацией, чтобы помочь вам в решении задач — используйте её с пониманием. Статья носит рекомендательный характер, поэтому, пожалуйста, применяйте описанные методы осмотрительно.