Оптимизация VPS под нагрузку: Nginx, PHP-FPM, MySQL, Redis
📖 Гайды

Как оптимизировать VPS под высокую нагрузку — настройка сервера и стека

Марина
Марина
📅 27 мая 2026 👁 121 просмотров
Как оптимизировать VPS под высокую нагрузку — настройка сервера и стека

VPS начинает тормозить не только потому что стало больше трафика — чаще всего причина в том, что сервер изначально настроен на дефолтах для «среднего случая», а не под конкретную нагрузку. Прежде чем оптимизировать VPS или покупать тариф дороже, стоит пройтись по стеку снизу вверх: ядро, диск, сеть, Nginx, PHP-FPM, база данных, кэш. На каждом слое есть рычаги, которые дают прирост без апгрейда железа.

Как понять, что VPS работает неэффективно

Как оптимизировать VPS под высокую нагрузку — настройка сервера и стека — иллюстрация

Диагностику начинают с трёх показателей. Load Average (top, htop) — если стабильно выше числа ядер, система перегружена. Swap (free -h) — активное использование swap означает нехватку RAM или неправильные настройки. Базовые симптомы: nginx возвращает 502/504, MySQL выдаёт «too many connections», время ответа сайта резко скачет под нагрузкой.

Для детальной картины — vmstat 1 5 покажет динамику CPU/mem/io, iostat -x 1 покажет утилизацию диска, atop даст историю нагрузки если проблема не постоянная, а пиковая. Задача этого этапа — понять, на каком слое стека узкое место, прежде чем начинать крутить параметры. О том, как настроить постоянный мониторинг, читайте в статье настройка мониторинга сервера.

Слой 1. Ядро Linux — системные параметры (sysctl)

Параметры ядра в /etc/sysctl.conf управляют тем, как система обрабатывает сеть, память и файловые дескрипторы. Дефолтные значения консервативны — для сервера под реальной нагрузкой их нужно скорректировать.

Базовый набор параметров для веб-сервера:

# /etc/sysctl.conf
vm.swappiness = 10
net.core.somaxconn = 65535
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
fs.file-max = 100000

Что делает каждый параметр. vm.swappiness = 10 — ядро будет использовать swap только при реальной нехватке RAM, а не при 40% заполненности (дефолт 60). net.core.somaxconn = 65535 — максимальный размер очереди входящих соединений; дефолт 128 — это очень мало для нагруженного сервера. net.ipv4.tcp_fin_timeout = 15 — время ожидания закрытия TCP-соединения, сокращение уменьшает количество соединений в состоянии TIME_WAIT. tcp_tw_reuse = 1 — разрешает повторное использование сокетов в TIME_WAIT. fs.file-max = 100000 — системный лимит открытых файлов.

Применить без перезагрузки: sysctl -p. Подробнее о параметрах — в документации ядра Linux.

Лимиты файловых дескрипторов (ulimit / limits.conf)

Системный лимит fs.file-max задаёт максимум для всей ОС, но каждый процесс ограничен отдельно через /etc/security/limits.conf. Для nginx и mysql нужно явно установить лимит:

# /etc/security/limits.conf
nginx    soft    nofile    65536
nginx    hard    nofile    65536
mysql    soft    nofile    65536
mysql    hard    nofile    65536

При большом числе соединений (тысячи одновременных пользователей) каждое соединение — это как минимум один файловый дескриптор. Если лимит исчерпан, nginx начнёт падать с ошибкой too many open files, и это не будет связано ни с CPU, ни с RAM.

Слой 2. Файловая система — диск и I/O

Планировщик I/O влияет на порядок обработки запросов к диску. Для SSD-дисков оптимален mq-deadline, для HDD — bfq. Проверить текущий: cat /sys/block/sda/queue/scheduler. Изменить для SSD: echo mq-deadline > /sys/block/sda/queue/scheduler. Чтобы изменение сохранялось после перезагрузки — нужно добавить правило udev.

Опция noatime в /etc/fstab запрещает обновление времени доступа при каждом чтении файла. На нагруженном сервере это снижает количество записей на диск. Выглядит в fstab так:

UUID=xxx / ext4 defaults,noatime 0 1

Файловая система: ext4 — стандарт и подходит для большинства случаев. XFS быстрее при параллельной записи и работе с большими файлами (медиа, логи, объектное хранилище). Для tmpfs под сессии PHP: монтировать /tmp или отдельную директорию сессий в оперативную память, если размер сессий небольшой и диск является узким местом.

Мониторинг I/O — как найти узкое место

iostat -x 1 показывает метрики диска в реальном времени. Ключевые поля: %util — утилизация диска; выше 80% означает, что диск работает на пределе. await — среднее время ожидания операции; для SSD больше 10ms — это уже признак проблемы. iotop покажет, какой именно процесс генерирует нагрузку на диск.

Слой 3. Сеть — TCP и очереди

В дополнение к параметрам из первого слоя, для высоконагруженных серверов стоит увеличить очереди входящих пакетов: net.core.netdev_max_backlog = 5000 и net.ipv4.tcp_max_syn_backlog = 8192. Это снижает потери соединений при пиках трафика. Подробнее о защите от перегрузки сети — в статье защита VPS от DDoS.

BBR — алгоритм управления перегрузкой от Google, доступен в ядрах 4.9+. Даёт прирост пропускной способности и снижает задержки, особенно при нестабильных соединениях. Включить:

# Проверить версию ядра
uname -r

# Включить BBR
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
sysctl -p

# Проверить что применилось
sysctl net.ipv4.tcp_congestion_control

Слой 4. Nginx — тюнинг веб-сервера

Nginx из коробки работает нормально, но дефолтные значения рассчитаны на умеренную нагрузку. Базовый тюнинг выглядит так:

worker_processes auto;
events {
    worker_connections 2048;
    use epoll;
    multi_accept on;
}
http {
    keepalive_timeout 15;
    sendfile on;
    tcp_nopush on;
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
    open_file_cache max=10000 inactive=30s;
    open_file_cache_valid 60s;
    open_file_cache_min_uses 2;
}

worker_processes auto — Nginx сам определит количество воркеров по числу ядер CPU. worker_connections 2048 — максимум соединений на один воркер. use epoll — эффективный механизм мультиплексирования I/O на Linux. multi_accept on — воркер принимает все новые соединения за один проход. open_file_cache кэширует дескрипторы открытых файлов и уменьшает количество системных вызовов. Подробнее о конфигурации — в официальной документации Nginx.

О сравнении Nginx и Apache с точки зрения нагрузки — статья Nginx или Apache — что выбрать.

Nginx + PHP-FPM — правильный fastcgi_pass

Nginx может передавать запросы в PHP-FPM через TCP-порт (127.0.0.1:9000) или Unix-сокет. На одном сервере Unix-сокет быстрее: нет сетевого стека, меньше overhead. Пример:

location ~ \.php$ {
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    fastcgi_read_timeout 60;
    fastcgi_buffer_size 16k;
    fastcgi_buffers 4 16k;
}

Слой 5. PHP-FPM — менеджер процессов

PHP-FPM управляет пулом рабочих процессов. Выбор режима pm — ключевое решение. dynamic — количество процессов меняется в диапазоне от pm.min_spare_servers до pm.max_children; подходит для большинства случаев. ondemand — процессы создаются по запросу и умирают после простоя; экономит память на небольших VPS. static — фиксированное количество процессов; максимальная производительность при стабильной нагрузке, но держит память даже в простое.

Формула для pm.max_children: разделить доступную RAM (за вычетом MySQL, Redis, системы) на средний размер одного PHP-процесса. Средний размер можно посмотреть через ps aux | grep php-fpm. Обычно 30–80 MB на процесс.

; /etc/php/8.2/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 8
pm.max_requests = 500

; /etc/php/8.2/fpm/php.ini (или conf.d/opcache.ini)
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.validate_timestamps=1

pm.max_requests = 500 — перезапуск процесса после 500 запросов предотвращает накопление утечек памяти в PHP-коде. OPcache кэширует скомпилированный байткод PHP — без него каждый запрос компилирует файлы заново. opcache.memory_consumption=128 для среднего проекта, 256 MB для крупного WordPress-мультисайта или большого фреймворка.

Слой 6. MySQL / MariaDB — база данных

InnoDB buffer pool — самый важный параметр MySQL. Это кэш в памяти для данных и индексов InnoDB. Правило: устанавливать в 60–70% от всей RAM сервера, если MySQL — единственная служба. На shared-сервере пересчитать исходя из доступной доли. Для сервера с 2 GB RAM и только MySQL — около 1,2–1,4 GB.

# /etc/mysql/conf.d/tuning.cnf
[mysqld]
innodb_buffer_pool_size = 512M
innodb_flush_log_at_trx_commit = 2
innodb_log_file_size = 128M
max_connections = 150
slow_query_log = 1
long_query_time = 1
slow_query_log_file = /var/log/mysql/slow.log
query_cache_size = 0
query_cache_type = 0

innodb_flush_log_at_trx_commit = 2 — данные пишутся в лог раз в секунду, а не при каждой транзакции. Даёт значительный прирост производительности при некритичных данных. Для финансовых транзакций оставлять значение 1. query_cache_size = 0 — query cache в MySQL 5.7+ и 8.0 официально устарел и удалён: при включении он создаёт конкуренцию за мьютексы и замедляет работу.

О переносе базы без потерь — статья как перенести базу данных MySQL.

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

После включения slow_query_log лог пишется в указанный файл. Анализировать вручную неудобно — использовать mysqldumpslow -t 10 /var/log/mysql/slow.log для топ-10 медленных запросов. Для глубокого анализа — pt-query-digest из Percona Toolkit.

Важный принцип: тюнинг my.cnf без оптимизации самих запросов даёт ограниченный эффект. Если запрос делает full table scan на таблице в 10 миллионов строк — никакой buffer pool это не исправит. Сначала индексы, потом параметры.

Слой 7. Кэш — Redis и Memcached

Как оптимизировать VPS под высокую нагрузку — настройка сервера и стека — иллюстрация

Redis — кэш с функциями: поддерживает структуры данных, опциональную персистентность (RDB/AOF), pub/sub, очереди. В веб-стеке используется для: кэширования страниц и объектов (WordPress Object Cache, Django Cache Framework), хранения сессий (быстрее, чем файлы на диске), очередей задач (Celery, Laravel Queue).

Базовые параметры в /etc/redis/redis.conf:

maxmemory 256mb
maxmemory-policy allkeys-lru

allkeys-lru — при достижении лимита Redis вытесняет наименее используемые ключи. Это поведение для кэша; для хранилища данных выбирать другую политику.

Memcached проще: только key-value кэш, без персистентности, без структур данных. Потребляет меньше памяти на одинаковых объёмах данных. Выбор: Redis если нужны структуры данных, persistence или очереди. Memcached — если только простое кэширование и важна максимальная простота конфига.

Swap — последний рубеж

Swap не заменяет оперативную память и не должен использоваться постоянно — это буфер для пиков, который предотвращает гибель процессов через OOM killer. Правило размера: для VPS с 1–4 GB RAM — swap равен RAM. Для 8+ GB — достаточно 4 GB.

# Создать swap-файл 2 GB
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# Сделать постоянным
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# Проверить
swapon --show

На серверах с очень ограниченной RAM (<1 GB) — рассмотреть zswap: это сжатый кэш swap-страниц прямо в RAM, значительно быстрее дискового swap при правильной нагрузке.

Мониторинг после оптимизации

Тюнинг без измерений — это гадание. После внесения изменений нужно убедиться, что они дали эффект, а не создали новое узкое место. Метрики для контроля: LA, свободная RAM, использование swap, количество активных соединений Nginx (stub_status), Threads_running в MySQL (SHOW STATUS LIKE 'Threads_running'), listen.queue в PHP-FPM (pm.status_path).

Инструменты: Netdata устанавливается одной командой и сразу показывает все метрики с историей. Prometheus + Grafana — если мониторинг уже есть в инфраструктуре. UptimeRobot — для внешней проверки доступности, чтобы видеть проблемы глазами пользователя.

Когда оптимизация не помогает — пора апгрейдить

Точечный тюнинг даёт 30–50% прироста производительности. Это существенно, но не бесконечно. Есть пороги, за которыми только смена тарифа или переход на выделенный сервер:

  • LA стабильно выше значения число ядер × 2 даже в ночное время
  • Swap заполнен на 80%+ постоянно (не при пиках)
  • InnoDB buffer pool hit rate ниже 95% (проверить: SHOW STATUS LIKE 'Innodb_buffer_pool%')
  • Диск утилизирован на 90%+ по iostat
  • Добавление RAM или CPU физически невозможно на текущем тарифе

Перед апгрейдом — сделать бэкап VPS: при переезде на новый тариф данные нужно переносить. О том, как выбрать следующий тариф — статья как выбрать VPS.

Если ресурсов VPS уже не хватает — сравните тарифы провайдеров на free-hosting.ru. Фильтр по RAM, CPU и типу дисков поможет найти подходящий вариант без переплаты. Выбрать VPS-провайдера →

Ну и в заключение — шпаргалка по слоям

Слой Ключевой параметр Эффект
Ядро (sysctl) vm.swappiness, somaxconn, tcp_fin_timeout Меньше swap, больше соединений, быстрее освобождение TCP
Диск I/O scheduler, noatime Меньше latency на SSD, меньше лишних записей
Сеть BBR, netdev_max_backlog Лучший throughput, меньше дропов при пиках
Nginx worker_connections, open_file_cache, gzip Больше одновременных соединений, меньше syscall
PHP-FPM pm.max_children, OPcache Меньше процессов-зомби, быстрый байткод-кэш
MySQL innodb_buffer_pool_size, slow_query_log Данные из RAM, видимость медленных запросов
Redis maxmemory, allkeys-lru Меньше запросов к PHP и MySQL, быстрые сессии
Swap Размер, swappiness Защита от OOM killer при пиках
Поделиться:
Марина
Редактор · FREEHOSTING
Главный редактор FREEHOSTING. С 2020 года тестирует VDS, VPS и хостинг-провайдеров — арендует серверы, нагружает их реальными проектами и пишет честные обзоры по итогам. Помогает читателям выбирать хостинг под свои задачи: от Telegram-бота до production-сайта.