Если сайт тормозит прямо сейчас, начни с команд ниже. Они есть почти на любом Linux-сервере, ставить ничего не нужно, и за минуту становится понятно, во что упёрся сервер: в процессор, в память, в диск или вообще ни во что. Как зайти на сервер, разобрано в статье о подключении к VPS по SSH.
nproc # сколько ядер (vCPU) видит система uptime # load average за 1, 5 и 15 минут top # строка %Cpu(s): смотри на us, wa и st free -h # колонка available, а не free df -h # место на дисках df -i # свободные inode vmstat 1 5 # колонки si/so (своп) и wa (ожидание диска)
Как читать то, что они выдали:
| Что видишь | Что это обычно значит | Куда смотреть дальше |
|---|---|---|
load average устойчиво выше nproc, в top высокий us | процессор занят реальной работой, процессы стоят в очереди | в top нажми Shift+P и найди, кто ест CPU |
load average высокий, но процессор почти свободен, заметный wa | очередь не к процессору, а к диску | раздел про диск, iostat -x 1 |
st держится выше 5–10% | процессорное время забирают соседи по физическому серверу | раздел про steal |
available меньше 10% памяти, в vmstat ненулевые si/so | памяти не хватает, сервер активно свопит | раздел про память, журнал ядра на OOM |
df -h или df -i показывают 100% | закончилось место или inode, сервисы не могут писать файлы | раздел про диск |
Всё это моментальный снимок. Он отвечает на вопрос «что происходит сейчас» и совершенно бесполезен, когда сайт лежал в три часа ночи, а к утру ожил сам. Для таких случаев нужна история, и включать её надо заранее, до первой аварии. Самый дешёвый вариант описан ниже, в разделе про sar и atop.
Load average и количество ядер
Load average выводят uptime, top и почти любая панель: три числа, среднее количество процессов, которые работают или ждут своей очереди, за последние 1, 5 и 15 минут. Без числа ядер эта цифра ничего не говорит. Load 4 на сервере с четырьмя vCPU означает, что процессор занят полностью, но очереди почти нет. Тот же load 4 на одном ядре значит, что три процесса постоянно стоят и ждут.
Короткие всплески минутного значения нормальны: запустился cron, пришла пачка поисковых ботов, отработал бэкап. Тревожиться стоит, когда выше числа ядер держится пятнадцатиминутное значение, ведь это уже не всплеск, а режим работы.
У Linux тут есть особенность, о которой в инструкциях пишут редко. В load average попадают не только процессы, которые хотят процессор, но и те, что застряли в ожидании диска (в top у них статус D). Поэтому бывает картина, которая сбивает с толку: load average за десять на двух ядрах, а процессор загружен процентов на двадцать. На клиентских серверах такое чаще всего случается во время ночного бэкапа, когда tar и mysqldump упираются в диск. Человек видит страшную цифру, идёт покупать тариф с большим числом ядер, и ему это не помогает ни на процент.
Разобраться помогает строка %Cpu(s) в top. us это время пользовательских программ (PHP, MySQL, Node.js), sy работа ядра, wa ожидание диска, st время, которое забрал гипервизор. Если высокий us, грузит код или база. Если высокий wa, проблема в дисковых операциях.
Ещё одна ловушка: общая цифра усредняется по всем ядрам. Однопоточный процесс, например PHP-скрипт импорта или приложение на Node.js, может упереться в одно ядро на 100%, а в шапке top на четырёх ядрах будут скромные 25%. Нажми в top клавишу 1, и загрузка разложится по ядрам. Что такое vCPU и почему два ядра на одном тарифе не равны двум ядрам на другом, разобрано в статье о vCPU.
Steal: процессор, который забрали соседи
Колонка st есть только на виртуальных серверах, и для владельца VPS это, пожалуй, самая полезная цифра из всех. Она показывает долю времени, когда твоя виртуальная машина хотела работать, а гипервизор отдавал физическое ядро кому-то другому. Внутри сервера эту нагрузку не видно никак: процессов, которые её создают, у тебя нет, они у соседей.
Несколько процентов steal на бюджетном тарифе встречаются постоянно, и на сайт они почти не влияют. А вот если st часами держится на 10–20% и выше, сайт тормозит без всякой видимой причины, и никакая оптимизация внутри сервера это не исправит. На тарифах с burstable-процессором похожая картина появляется, когда закончился запас «кредитов» и провайдер урезал ядро до базовой доли, подробнее в статье о shared и dedicated CPU. Полезно собрать историю через sar -u (о нём ниже): с графиком steal за неделю разговор с поддержкой идёт совсем иначе, чем со словами «у меня всё тормозит».
Кстати, на контейнерных VPS (OpenVZ, LXC) steal обычно не показывается вовсе, а часть цифр внутри, вроде объёма памяти или load average, ядро подменяет или берёт у хоста. Если цифры в top выглядят странно, сначала проверь, какая у тебя виртуализация, разница описана в статье KVM против OpenVZ.
Память: «занято 90%» ещё не беда
Типичный вывод free -h на маленьком VPS:
total used free shared buff/cache available Mem: 1.9Gi 1.1Gi 95Mi 42Mi 820Mi 680Mi Swap: 1.0Gi 210Mi 814Mi
Свободно 95 мегабайт из двух гигабайт, и это нормально. Linux занимает всю незанятую память под кэш файлов, чтобы не читать одно и то же с диска, и отдаёт её программам по первому требованию. Реальный запас показывает колонка available: здесь это 680 мегабайт, т.е. треть памяти. Обращения в духе «память забита на 95%, сервер вот-вот упадёт» провайдеры получают постоянно, и в большинстве случаев человек смотрит на график, где кэш сложен вместе с занятой памятью.
Со свопом похожая история. Двести мегабайт в swap сами по себе ничего не значат: ядро могло вытеснить туда страницы, которые никто не трогал с прошлого месяца. Плохо, когда своп используется активно, т.е. страницы постоянно уходят на диск и возвращаются обратно. Это видно в vmstat 1: колонки si и so на здоровом сервере почти всегда нули. Если там стабильно сотни и тысячи, сайт замедляется в разы, а сервер ощущается «ватным». Как настроить swap-файл и сколько его ставить, разобрано в статье о swap на VPS.
Когда кончаются и память, и своп, срабатывает OOM killer: ядро выбирает процесс, который занимает больше всего памяти, и убивает его. На сервере с сайтом это почти всегда MySQL или MariaDB, просто потому что база самая крупная. Сайт отвечает «Error establishing a database connection», после рестарта базы всё работает, и так до следующего раза. Проверить, был ли OOM, можно по журналу ядра:
journalctl -k | grep -iE "out of memory|killed process"
Самый частый сценарий на VPS с одним-двумя гигабайтами выглядит так. В пуле PHP-FPM разрешено, скажем, 30 дочерних процессов, каждый под нагрузкой занимает от 40 до 100 с лишним мегабайт, и в обычный день их работает пять-шесть. Приходит волна ботов, PHP-FPM честно поднимает все тридцать, память заканчивается, и ядро убивает базу, которая вообще ни при чём. Лечится это ограничением pm.max_children под реальный объём памяти, подробнее в статье об оптимизации PHP-FPM.
Диск: место, inode и очередь
Под словами «проблемы с диском» прячутся три разные вещи, и проверяются они по-разному.
Место. df -h показывает заполненность разделов. На 100% база перестаёт писать, сессии не создаются, nginx сыплет ошибками, а иногда сервер даже не пускает по SSH с паролем. Виноваты обычно логи, старые бэкапы, которые складываются на тот же диск, и образы Docker. Найти, куда ушли гигабайты:
sudo du -xh --max-depth=1 / 2>/dev/null | sort -h
Дальше идёшь вглубь по самому большому каталогу. Подробно об этом в статьях об очистке места на диске и о ротации логов.
Inode. Каждый файл, даже пустой, занимает одну запись в таблице inode, и их количество на разделе ограничено. Сайт, который годами копит миллионы мелких файлов (кэш плагина, PHP-сессии, превьюшки), может исчерпать inode при свободных 40% места. Ошибка при этом та же, No space left on device, поэтому её так долго ищут: df -h показывает, что места полно. Помогает df -i.
Скорость. Тут нужен iostat из пакета sysstat:
sudo apt install sysstat iostat -xz 1
Смотри на r_await и w_await, среднее время ожидания операции в миллисекундах. На нормальном SSD или NVMe это единицы, иногда десятки при всплесках. Сотни миллисекунд означают, что диск не справляется или его делят с кем-то ещё. На колонку %util многие ориентируются по старой памяти, и зря: для SSD, NVMe и сетевых хранилищ, которые обрабатывают много запросов параллельно, 100% в ней не значит, что диск упёрся в предел. Кто именно пишет на диск, покажет sudo pidstat -d 1 из того же пакета.
Сеть
На маленьком VPS сеть редко становится узким местом, но две вещи проверить полезно. ss -s показывает число соединений: если их вдруг стало в десятки раз больше обычного, а процессор при этом ушёл в потолок, похоже на наплыв ботов или атаку, об этом статьи о DDoS и о Fail2ban. А если на тарифе есть лимит трафика, поставь vnstat: он тихо считает трафик по дням и месяцам и почти не потребляет ресурсов.
PSI: одна цифра о том, что серверу тесно
У load average есть недостаток: он не говорит, какого ресурса не хватает. В ядре Linux начиная с версии 4.20 есть механизм PSI (pressure stall information), который отвечает именно на этот вопрос:
cat /proc/pressure/cpu /proc/pressure/memory /proc/pressure/io
some avg10=0.00 avg60=0.42 avg300=0.31 total=81234567 full avg10=0.00 avg60=0.00 avg300=0.00 total=0 some avg10=12.71 avg60=9.84 avg300=6.02 total=912345678 full avg10=4.10 avg60=3.22 avg300=1.95 total=301234567 some avg10=1.03 avg60=0.88 avg300=0.64 total=45678901 full avg10=0.51 avg60=0.40 avg300=0.33 total=23456789
Числа здесь проценты времени за последние 10, 60 и 300 секунд. some значит, что хотя бы часть процессов стояла и ждала ресурс, full значит, что ждали все сразу и полезная работа не шла вообще. В примере выше процессор свободен, диск в порядке, а память уже душит сервер: 12% времени процессы ждут, пока ядро найдёт им страницы. До OOM ещё далеко, а сайт уже тормозит. Жёстких порогов нет, но устойчивые значения some в несколько процентов по памяти или диску на небольшом сайте обычно стоят того, чтобы разобраться.
На Ubuntu и Debian PSI работает из коробки. На AlmaLinux и Rocky Linux он может быть выключен по умолчанию и включается параметром ядра psi=1. Netdata и node_exporter умеют рисовать эти показатели на графиках, так что разглядывать файлы руками каждый раз не придётся.
Кто именно грузит
Общие цифры показали, что не так. Следующий шаг: найти процесс. В top клавиша Shift+P сортирует по процессору, Shift+M по памяти. В htop то же самое через F6, плюс там удобнее смотреть дерево процессов. Без интерактива:
ps aux --sort=-%cpu | head -n 10 ps aux --sort=-%mem | head -n 10 systemd-cgtop
systemd-cgtop недооценён. Он показывает потребление не по процессам, а по сервисам целиком, и тридцать дочерних процессов PHP-FPM, каждый из которых в top выглядит скромно, складываются в одну строку с реальной суммой. Для контейнеров то же самое делает docker stats. Стоит его запустить, и нередко выясняется, что память ест не сам сайт, а тестовый контейнер, который так и висит с прошлого месяца. О контейнерах подробнее в статье о Docker на VPS.
Отдельный случай, который выглядит как нагрузка, а на деле совсем другое: процесс со странным именем из случайных букв, который занимает все ядра на 100% круглосуточно. Чаще всего это майнер, поселившийся после взлома. Убить процесс мало, он вернётся через cron или systemd, тут нужен порядок действий из статьи о признаках взлома VPS.
Если в верхних строчках прочно сидит mysqld, смотреть дальше нужно уже внутри базы: SHOW FULL PROCESSLIST; покажет запросы, которые выполняются прямо сейчас, а медленный лог укажет на те, что тормозят регулярно. Это тема статьи об оптимизации MySQL.
История нагрузки: sar и atop
Самая частая ситуация, с которой приходят к провайдеру: «ночью сайт лежал, сейчас всё нормально, что это было?». Без истории ответ один: неизвестно. Можно гадать по логам nginx, но причину, т.е. что творилось с памятью и процессами в 03:10, они не покажут.
Минимальный набор, который стоит включить на любом сервере в первый же день, весит несколько мегабайт и не требует никакого веб-интерфейса. Первый инструмент sar из пакета sysstat, он раз в десять минут записывает загрузку процессора (включая steal), памяти, свопа, дисков и сети. На Debian и Ubuntu после установки сбор данных бывает выключен, это нужно проверить:
sudo apt install sysstat grep ENABLED /etc/default/sysstat sudo sed -i 's/ENABLED="false"/ENABLED="true"/' /etc/default/sysstat sudo systemctl enable --now sysstat
Через пару часов уже есть что посмотреть:
sar -q # load average за сегодня sar -u -s 02:00:00 -e 04:00:00 # процессор и steal с 2 до 4 ночи sar -r # память sar -B # активность подкачки страниц sar -d -p # диски
Данные за прошлые дни лежат в /var/log/sysstat, по файлу на число месяца, и открываются ключом -f. Хранятся они от недели до месяца, в зависимости от дистрибутива и настроек в /etc/sysstat/sysstat.
sar скажет, что в 03:10 закончилась память, но не скажет, кто её съел. Для этого второй инструмент, atop. В пакетах Debian и Ubuntu он после установки обычно сам начинает писать журнал с полным списком процессов каждые десять минут:
sudo apt install atop atop -r /var/log/atop/atop_20261002
В режиме просмотра клавиша t листает вперёд по времени, Shift+T назад, а Shift+M сортирует по памяти. Найти процесс-виновника ночного падения так можно за пару минут. Цена вопроса: журналы atop за несколько недель занимают сотни мегабайт, на крошечном диске за этим стоит присматривать.
Вообще удивительно, сколько серверов работает годами без всякой истории, хотя включить её проще, чем поставить любой плагин на сайт.
Netdata, Prometheus с Grafana, Zabbix: что ставить на один VPS
Консольных инструментов хватает, чтобы разобраться в проблеме. Графики нужны, когда хочется видеть тренды без командной строки, получать уведомления и следить за несколькими серверами сразу. Вариантов много, но на практике выбирают из трёх-четырёх.
| Инструмент | Что даёт | Чем платишь | Кому подходит |
|---|---|---|---|
| sysstat + atop | история в консоли, процессы на момент сбоя | почти ничем | любому серверу, ставится первым |
| Netdata | сотни метрик с секундной детализацией, готовые алерты, установка за пять минут | по данным разработчиков около 150 МБ памяти и несколько процентов CPU, закрытая лицензия у веб-интерфейса | одному-двум серверам, когда хочется видеть всё и сразу |
| Prometheus + node_exporter + Grafana | гибкие дашборды, долгое хранение, правила алертов, стандарт индустрии | три сервиса, настройка руками, несколько сотен мегабайт памяти | нескольким серверам или тем, кто хочет освоить стандартный стек |
| Zabbix | агенты на серверах, центральный сервер с базой, шаблоны и алерты | отдельная база данных и веб-интерфейс, тяжеловато для VPS с 1 ГБ | парку серверов, сетевому оборудованию |
Netdata для одиночного VPS обычно самый удобный выбор, но у него есть три момента, о которых лучше знать до установки. Первый: устанавливается он скриптом разработчиков, т.к. из официальных репозиториев Debian пакет убрали, в том числе из-за того, что новый веб-интерфейс распространяется под собственной несвободной лицензией (сам агент остаётся под GPL). Второй: по умолчанию скрипт ставит nightly-сборки, включает автообновления и анонимную телеметрию. Если тебе это не нужно, удобнее сразу указать стабильный канал и выключить телеметрию:
wget -O /tmp/netdata-kickstart.sh https://get.netdata.cloud/kickstart.sh DISABLE_TELEMETRY=1 sh /tmp/netdata-kickstart.sh --release-channel stable
Третий момент самый неприятный. Веб-интерфейс Netdata слушает порт 19999 на всех адресах сервера, и если файрвол его не закрывает, графики нагрузки, имена сервисов и много чего ещё видит любой, кто догадается зайти на этот порт. Открытые панели Netdata на клиентских серверах попадаются регулярно. Проще всего привязать интерфейс к localhost. В /etc/netdata/netdata.conf (при установке статической сборкой он лежит в /opt/netdata/etc/netdata/):
[web]
bind to = 127.0.0.1 После sudo systemctl restart netdata интерфейс открывается через SSH-туннель: на своём компьютере выполняешь ssh -L 19999:127.0.0.1:19999 user@адрес_сервера и заходишь в браузере на http://localhost:19999. Закрыть порт файрволом тоже можно, об этом статья о UFW и iptables. Подробный разбор Netdata будет в отдельной статье про Netdata.
Связку Prometheus и Grafana стоит брать, когда серверов несколько или хочется хранить метрики месяцами и строить свои дашборды, она разобрана в статье о Grafana и Prometheus. Держать её на том же VPS за 1–2 ГБ, который она мониторит, неудобно: мониторинг сам отъедает заметную долю памяти и падает вместе с сервером. Разумнее поставить на рабочие серверы только лёгкий node_exporter, а Prometheus с Grafana вынести на отдельную маленькую машину.
Munin, VictoriaMetrics, Glances, коммерческие SaaS-сервисы… выбор огромный, и почти любой из них лучше, чем никакого мониторинга. Но для одного сайта на одном VPS sysstat с atop плюс Netdata закрывают девять задач из десяти.
Алерты и почему главную проверку ставят снаружи
Мониторинг, который живёт на самом сервере, умирает вместе с ним. Если VPS завис, ядро упало в панику или у провайдера пропала сеть, Netdata никому ничего не отправит: отправлять уже некому. Поэтому главная проверка, «сайт открывается или нет», должна идти снаружи, с другого сервера или из внешнего сервиса. Самый простой вариант для своего хозяйства описан в статье об Uptime Kuma.
Внутренние алерты нужны для другого: чтобы узнать о проблеме до того, как она стала аварией. Здесь важнее не количество правил, а пороги. Алерт на «процессор выше 90%» без привязки ко времени будет срабатывать на каждый бэкап и каждый наплыв ботов. Через неделю такие письма перестают читать, через месяц их отправляют в отдельную папку, и настоящую аварию в ней уже никто не замечает. Картина эта настолько типичная, что можно смело закладывать её в планы.
Рабочие пороги для начала, которые потом подстраиваются под конкретный сервер: диск заполнен больше чем на 80–85%; load average выше числа ядер дольше 10–15 минут; доступная память меньше 10% вместе с активным свопом; любой OOM в журнале ядра; steal выше 10% дольше получаса. У Netdata большая часть этого есть в готовых алертах, их остаётся подключить к почте или Telegram.
Графики в панели провайдера
Если ничего не ставить, у тебя всё равно есть графики в панели управления VPS. Их снимает гипервизор снаружи виртуальной машины: процессор всей машины, диск, сетевой трафик. Для грубой истории это полезно, процессы и причины они не показывают. С памятью там бывает неразбериха: гипервизор не отличает кэш файлов от занятой программами памяти и часто рисует почти всю память занятой. Расхождение между графиком провайдера и top внутри сервера нормально, верить в спорных случаях стоит тому, что показывает сама система.
Нагрузка высокая: апгрейд или оптимизация
Мониторинг нужен не ради красивых графиков, а чтобы понять, за что платить деньги и что чинить бесплатно. Каждая картина подсказывает своё.
Высокий us, и в верху списка процессы PHP. Почти всегда сначала помогает кэширование: страничный кэш, object cache через Redis, и тот же сервер вдруг выдерживает в разы больше посетителей. Об этом статьи об ускорении сайта на VPS и о Redis и Memcached. Высокий wa и медленный диск: тяжёлые запросы к базе, бэкап в час пик или просто слабое хранилище у провайдера. Нехватка памяти: лимиты PHP-FPM и буферы базы под реальный объём RAM, своп как подушка безопасности. Высокий steal: внутри сервера оптимизировать нечего, помогает только другой тариф или другой провайдер.
Апгрейд оправдан, когда после очевидных оптимизаций ресурс всё равно стабильно упирается в предел, а по истории sar за месяц видно, что нагрузка растёт, а не скачет. Тогда это не авария, а нормальный рост проекта, и вопрос уже в том, увеличивать сервер или добавлять второй, разница описана в статье о вертикальном и горизонтальном масштабировании. Сколько реально выдерживает текущий сервер, лучше узнать заранее, нагрузочным тестом, а не в день распродажи: об этом статья о бенчмарке и стресс-тесте VPS.
В старых советах по VPS до сих пор встречается рекомендация «периодически перезагружать сервер, чтобы освободить ресурсы». Выглядит логично, но работает против тебя. Если память день за днём растёт, пока сервер не перезапустишь, это утечка в конкретном сервисе, и перезагрузка прячет симптом, а заодно стирает все улики. При включённых sar и atop видно, какой процесс растёт, и перезапускать или чинить нужно именно его. Здоровый Linux-сервер спокойно работает месяцами, перезагружаясь только ради обновлений ядра.
Источники
- top(1) – Linux manual page
- free(1) – Linux manual page
- proc_meminfo(5): MemAvailable и другие поля – Linux manual page
- vmstat(8) – Linux manual page
- iostat(1) – Linux manual page
- PSI – Pressure Stall Information – документация ядра Linux
- sysstat – официальный сайт проекта
- sysstat – Debian Wiki
- atop – официальный сайт проекта
- systemd-cgtop – документация systemd
- Install Netdata with kickstart.sh – документация Netdata
- Access Control and Feature Availability – документация Netdata
- netdata – Debian Package Tracker
- Monitoring Linux host metrics with the Node Exporter – документация Prometheus
- Zabbix Documentation – официальное руководство

