Высокая нагрузка на сервер
Если VPS стал отвечать медленно, сайты подвисают, а SSH еле реагирует на ввод — вероятная причина в высокой нагрузке. В этой статье — как измерить нагрузку и понять, много это или мало именно для вашего сервера, как найти конкретный процесс или причину, которая её создаёт (CPU, память или диск), и какое решение подходит: ограничить или остановить процесс, добавить подкачку, оптимизировать конфигурацию — или перейти на тариф с большими ресурсами.
Что понадобится
- Доступ по SSH под
rootили пользователем сsudo— все команды ниже выполняются в терминале. - Желательно (необязательно) — доступ к панели VMmanager 6: пригодится, чтобы посмотреть графики CPU/RAM/диска за долгий период и, если понадобится, увеличить ресурсы сервера. Если ещё не заходили — см. статью «Как войти в VMmanager 6».
Шаг 1. Оцените load average и сравните его с числом ядер
Быстрее всего понять, насколько сервер загружен, — команда uptime:
uptimeПример вывода:
14:32:07 up 21 days, 3:12, 2 users, load average: 0.52, 0.58, 0.61Три числа после load average — это средняя длина очереди процессов, готовых выполняться (состояние R) или ожидающих дисковый ввод-вывод (состояние D), усреднённая за последние 1, 5 и 15 минут. Это не проценты загрузки CPU — это количество процессов, которым в среднем не хватало свободного ядра или диска прямо сейчас.
Сами по себе эти числа ничего не значат без числа ядер CPU на сервере:
nprocРазделите load average на результат nproc — получится средняя занятость в пересчёте на одно ядро:
- Все три числа около
1.0на ядро или ниже — сервер справляется с нагрузкой. - 1-минутное значение заметно выше 5- и 15-минутного — короткий всплеск (отработал cron, разовый наплыв запросов), обычно не повод для беспокойства.
- 5-минутное и особенно 15-минутное значение устойчиво выше
1.0на ядро — нагрузка не разовая, процессы реально простаивают в очереди за CPU или диском.
Те же три числа видно и в шапке top — отдельно uptime нужен, только если хочется глянуть быстро, не открывая интерактивный интерфейс:
topПо умолчанию top показывает загрузку CPU одной суммарной строкой %Cpu(s). Нажмите 1, чтобы переключиться на отдельную строку по каждому ядру — так сразу видно, размазана нагрузка равномерно или упирается в одно-единственное ядро (типичный симптом однопоточного узкого места, когда общий load average в пересчёте на все ядра выглядит невысоким, а реально всё упирается в одно ядро).
Шаг 2. Найдите процесс, который нагружает сервер
top по умолчанию сортирует процессы по %CPU — самый нагруженный процесс сразу окажется наверху:
topДля снимка без интерактивного режима — удобно скопировать вывод или сохранить в лог:
top -bn1 | head -20Если предпочитаете более наглядный интерфейс — поставьте htop:
Ubuntu / Debian:
sudo apt install htopAlmaLinux / Rocky (htop не входит в стандартные репозитории — сначала подключите EPEL):
sudo dnf install -y epel-release
sudo dnf install -y htophtopПо умолчанию htop тоже сортирует по %CPU и сразу показывает отдельную шкалу загрузки для каждого ядра вверху экрана. Клавиша F6 открывает выбор поля сортировки (например, по памяти), F9 — отправить процессу сигнал (в том числе завершить) прямо из списка, не выходя в отдельный терминал.
Без интерактивного режима, для сортировки по CPU или по памяти отдельно:
ps aux --sort=-%cpu | head -10ps aux --sort=-%mem | head -10Из всех столбцов вывода в первую очередь важны PID, %CPU, %MEM и COMMAND. Столбец STAT использует те же обозначения состояния, что и S в top: R — выполняется, D — ожидает дисковый ввод-вывод (если видите здесь D у процесса из верхних строк — вероятная причина не CPU, а диск, см. Шаг 5), S — спит, Z — зомби.
По тому, как выглядит список, можно сразу понять направление:
- Один процесс явно выделяется по
%CPUили%MEMна фоне остальных — «сбежавший» процесс, см. Шаг 6, «Один процесс вышел из-под контроля». - Нагрузка размазана по десяткам однотипных процессов (много
php-fpm,node, воркеров вашего веб-сервера или приложения) — это не поломка одного процесса, а реальная нагрузка от трафика или не подстроенная под сервер конфигурация приложения, см. Шаг 6, «Легитимная нагрузка или плохо настроенное ПО».
Шаг 3. Проверьте память и swap
Даже если с CPU всё в порядке, нехватка оперативной памяти тормозит весь сервер целиком — через активный своп.
free -hПример вывода:
total used free shared buff/cache available
Mem: 3.8Gi 2.9Gi 120Mi 45Mi 900Mi 650Mi
Swap: 2.0Gi 1.6Gi 412MiСмотрите на колонку available в строке Mem — это не «свободная» память в буквальном смысле, а оценка того, сколько реально можно выделить новым процессам без ухода в своп (с учётом кеша страниц, который ядро может вытеснить). Если available мало, а в строке Swap значение used велико и продолжает расти — это давление на память.
Проверьте, вообще настроен ли своп на сервере:
swapon --showПустой вывод означает, что подкачки нет вообще — тогда при нехватке RAM у ядра остаётся только один выход, описанный в Шаге 4.
Активность свопа прямо сейчас показывает vmstat:
vmstat 1 5Колонки si и so — сколько килобайт в секунду читается из подкачки и пишется в неё. Устойчиво ненулевые значения означают, что сервер прямо сейчас активно свопит: доступ к «памяти» на деле идёт через диск, который на порядки медленнее RAM, — отсюда и общее ощущение подвисания, даже если %CPU отдельных процессов выглядит не так уж высоко.
Шаг 4. Проверьте, не сработал ли OOM killer
Когда оперативная память и своп заканчиваются полностью, ядро Linux не просто тормозит — оно принудительно завершает один из процессов, чтобы система вообще осталась жива (OOM killer, Out-Of-Memory killer). Это объясняет внезапные падения именно самого «тяжёлого» процесса (часто СУБД или другого сервиса с большим потреблением памяти) без единой ошибки в логах самого приложения.
sudo dmesg -T | grep -Ei 'out of memory|killed process'Пример строки в выводе:
[Thu Jul 9 11:47:02 2026] Out of memory: Killed process 18342 (mysqld) total-vm:2145392kB, anon-rss:1583020kB, file-rss:0kB, shmem-rss:0kB, UID:112 pgtables:3456kB oom_score_adj:0Кольцевой буфер dmesg очищается при перезагрузке сервера. Чтобы поискать такие события за более долгий период, используйте системный журнал — те же сообщения ядра, но хранятся между перезагрузками:
sudo journalctl -k --no-pager | grep -Ei 'out of memory|killed process'Если такие записи нашлись — это подтверждает, что в этот момент именно память (а не CPU или диск) была узким местом. Переходите к Шагу 6, «Не хватает оперативной памяти», а при повторяющихся случаях — к «Ресурсов объективно не хватает — апгрейд тарифа».
Шаг 5. Проверьте дисковую нагрузку (I/O)
Высокая нагрузка иногда упирается не в CPU и не в память, а в сам диск — процессы простаивают в очереди в состоянии D, ожидая, пока диск обработает чтение или запись.
Утилита iostat идёт в составе пакета sysstat — он есть в стандартных репозиториях всех целевых дистрибутивов, EPEL не требуется:
Ubuntu / Debian:
sudo apt install sysstatAlmaLinux / Rocky:
sudo dnf install -y sysstatЗапустите с расширенной статистикой:
iostat -xz 1 3-x — расширенная статистика (в том числе %util и await), -z — не показывать диски без активности за интервал, 1 3 — три отчёта с интервалом в 1 секунду. Первый отчёт iostat всегда показывает средние значения с момента загрузки сервера — ориентируйтесь на второй и последующие отчёты, которые отражают именно текущий интервал.
Пример (сокращённо — показаны не все столбцы реального вывода):
Device r/s w/s %util await
vda 12.40 58.20 97.50 42.30%util— доля времени, в течение которого к диску были обращения. Для одиночного диска значение, близкое к 100%, почти всегда значит, что диск — узкое место. Для RAID-массива из нескольких дисков этот показатель не так однозначен: устройство может обслуживать несколько запросов параллельно.await— среднее время выполнения запроса в миллисекундах, включая и ожидание в очереди, и само обслуживание. На SSD/NVMe в норме это единицы миллисекунд; устойчивые десятки-сотни миллисекунд — явный признак, что диск не справляется.
Шаг 6. Частые причины и что делать
Один процесс вышел из-под контроля
Если в Шаге 2 нашёлся конкретный процесс-виновник — сначала попробуйте завершить его штатно:
kill -TERM 18342Если через несколько секунд процесс всё ещё жив — завершите принудительно:
kill -9 18342Если это управляемая через systemd служба (веб-сервер, СУБД и подобное), правильнее не убивать процесс напрямую, а перезапустить саму службу — так она поднимется в чистом состоянии:
sudo systemctl restart mysqlИмя службы у вас может быть другим — например, если это СУБД, см. статьи «MySQL / MariaDB: установка и настройка» или «Redis: установка и настройка».
Если убивать процесс не хочется, а хочется просто сделать его менее жадным, понизьте ему приоритет CPU:
sudo renice -n 15 -p 18342Диапазон значений — от -20 (наивысший приоритет) до 19 (низший). Процесс не завершается, но при конкуренции за CPU уступает остальным.
Чтобы жёстко ограничить долю CPU (например, не больше 50% одного ядра), не трогая приоритет, используйте cpulimit:
Ubuntu / Debian:
sudo apt install cpulimitAlmaLinux / Rocky (нужен EPEL — если уже подключали его для htop, повторно подключать не требуется):
sudo dnf install -y epel-release
sudo dnf install -y cpulimitcpulimit -p 18342 -l 50cpulimit работает в реальном времени на переднем плане. Чтобы ограничение продолжало действовать и после закрытия SSH-сессии, запустите его в фоне: cpulimit -p 18342 -l 50 &.
Для systemd-службы такое ограничение надёжнее задать самому systemd — оно переживёт перезапуск процесса и не требует отдельно висящей утилиты:
sudo systemctl set-property mysql.service CPUQuota=50% MemoryMax=1GПрименяется сразу, без перезапуска службы, и сохраняется после перезагрузки сервера.
Не хватает оперативной памяти
df -h /Если места впритык или не хватает — сначала разберитесь со статьёй «Диск заполнен».
Создайте файл подкачки (размер 2G — пример, подберите под объём памяти и свободное место на вашем сервере):
sudo fallocate -l 2G /swapfilesudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progressОграничьте права на файл, инициализируйте его как своп и включите:
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfileЧтобы своп подключался автоматически после перезагрузки, добавьте запись в /etc/fstab:
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstabПроверьте результат:
sudo swapon --show
free -hДополнительно можно снизить vm.swappiness — параметр ядра (по умолчанию 60, диапазон 0–200), который определяет, насколько охотно ядро уходит в своп вместо того, чтобы вытеснять кеш страниц:
sudo sysctl vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.confЛегитимная нагрузка или плохо настроенное ПО
- Число воркеров/процессов не соответствует числу ядер — слишком много воркеров конкурируют за одни и те же ядра, слишком мало — не используют все доступные. Ориентируйтесь на
nprocи рекомендации для конкретного стека: «Python и FastAPI: продакшн-деплой», «Django на VPS», «Node.js приложение с PM2 и Nginx». - СУБД не ограничена по памяти и конкурирует за неё с остальными процессами — настройте буферы под реальный объём RAM сервера: «MySQL / MariaDB: установка и настройка», «PostgreSQL: установка и настройка». Для Redis — директива
maxmemoryвместе с политикой вытесненияmaxmemory-policy, см. «Redis: установка и настройка». - Бэкап или другое задание cron попало на то же время, что и пик нагрузки — сверьте время всплеска load average из Шага 1 с расписанием задач:
crontab -lsystemctl list-timersЕсли совпало — перенесите тяжёлые задачи на менее загруженное время суток: «Автобэкапы по расписанию (cron)», «Инкрементальные бэкапы с restic», «Резервное копирование с rsync».
- Запросы к базе без индексов, N+1-запросы, отсутствие кеширования — самая частая причина ситуации «трафик вроде бы не вырос, а нагрузка выросла». Это уже вопрос кода и конфигурации приложения, а не самого VPS.
Ресурсов объективно не хватает — апгрейд тарифа
Если после отключения/ограничения лишних процессов и оптимизации сервер всё равно стабильно упирается в потолок под реально необходимой нагрузкой — вероятно, пора расти вместе с проектом, а не бороться с симптомами.
- Посмотрите графики CPU/RAM/диска за последние дни или недели в карточке сервера в VMmanager 6 — если нагрузка стабильно высокая, а не разовый всплеск, это и есть сигнал, что текущему тарифу не хватает ресурсов на ваш проект.
📷 [скриншот: график загрузки CPU/RAM сервера в карточке VPS в VMmanager 6]
- Апгрейд vCPU, RAM или диска оформляется в личном кабинете my.mhost.ee (либо через поддержку MHost).
Если сервер похоже взломан
Иногда то, что выглядит как «нагрузка от трафика», на самом деле не имеет отношения ни к вашему приложению, ни к легитимным посетителям — сервер может быть взломан и использоваться для майнинга криптовалюты, рассылки спама или участия в DDoS-атаках. Признаки, что дело не в конфигурации, а во взломе:
- В списке процессов (Шаг 2) — незнакомое имя, которое вы не устанавливали, особенно запущенное из
/tmp,/var/tmpили/dev/shm. - Процесс завершаете (
kill -9), а через несколько секунд он появляется снова — с тем же или другим PID. - Резко выросла исходящая сетевая активность без видимой причины:
sudo ss -tnp- В
crontab -lили файлах/etc/cron.d/есть задания, которые вы точно не добавляли.
Что дальше
Если после всех шагов сервер всё равно периодически «проседает» именно под пиковой, но реально необходимой нагрузкой — скорее всего, дело не в разовой поломке, а в том, что текущему тарифу пора расти вместе с проектом (см. Шаг 6 выше). Смежные темы: если из-за нагрузки сайт не просто тормозит, а не открывается совсем — статья «Сайт не открывается»; если не запускается сама служба, а не просто потребляет много ресурсов, — статья «Служба не запускается»; если больше похоже на нехватку места на диске, а не CPU/RAM, — статья «Диск заполнен».