Skip to content
EN
← Все статьи

Высокая нагрузка на сервер: как найти причину за 15 минут

Коротко. Начните с uptime и nproc — load average сравнивают с числом ядер, а не с единицей. Затем vmstat 1 разделяет три разные «нагрузки»: очередь на CPU (колонка r), ожидание диска (b и wa) и свопинг (si/so). Дальше — free -h, df -h и df -i, iostat -x 1, ss -s. Виновника ищут через ps aux --sort=-%cpu и логи nginx, PHP-FPM и базы.

«Сервер тормозит» — это не диагноз, а симптом. За одинаковой картиной (сайт отвечает медленно или отдаёт 502/503) стоят принципиально разные причины: нехватка процессора, ожидание диска, свопинг, забитый раздел, всплеск соединений, один тяжёлый SQL-запрос или наплыв парсеров. Лечение у них разное, и добавление ядер помогает ровно в одном случае из шести. Ниже — последовательность команд, которая за 15 минут сужает круг до одного слоя, и то, что делать дальше.

Схема диагностики нагрузки на сервер: от load average к четырём ветвям — CPU, память, диск, сеть
Диагностика идёт сверху вниз: сначала общая картина, потом конкретный ресурс, потом конкретный процесс.

Первые 60 секунд: load average, top и vmstat

Задача первой минуты — не найти виновника, а понять, какой ресурс исчерпан. Три команды дают 80% ответа.

uptime
nproc
vmstat 1 5
free -h
df -h; df -i

Как читать load average и почему «load 4» на 4 ядрах — не всегда плохо

Вывод uptime заканчивается тремя числами: средняя нагрузка за 1, 5 и 15 минут.

$ uptime
 14:22:31 up 82 days,  3:11,  2 users,  load average: 4.12, 3.87, 2.05
$ nproc
4

Load average в Linux — это среднее число задач, которые либо выполняются на процессоре, либо стоят в очереди на него, либо находятся в состоянии непрерываемого сна (D — обычно ожидание дискового ввода-вывода). Это принципиальное отличие от классического UNIX: в Linux в load попадает и диск, поэтому load 30 при простаивающем CPU — нормальная картина для сервера, который упёрся в диск или в сетевое хранилище.

Нормализуйте load на число ядер. Load 4.12 на четырёх ядрах — это загрузка около 100%: система работает на пределе, но очередь ещё не растёт лавинообразно. Тот же 4.12 на 16 ядрах — четверть мощности, повода для тревоги нет. Тот же 4.12 на одном ядре означает, что каждая задача в среднем ждёт в очереди в три раза дольше, чем выполняется.

Сравнение трёх чисел важнее их абсолютного значения. Ряд 4.12 / 3.87 / 2.05 означает рост — нагрузка началась недавно и усиливается. Ряд 2.05 / 3.87 / 4.12 означает спад: пик уже прошёл, и, возможно, вы диагностируете последствия, а не причину. Ровный ряд — устойчивое состояние, и его надо сравнивать с историей, а не с ощущениями.

Load average сам по себе не отвечает на вопрос «почему». Он отвечает только на вопрос «сколько задач ждут». Пока вы не разделили ожидание CPU и ожидание диска, любые действия — угадывание.

Что смотреть в top и htop

В top полезны не все колонки. Смотрите на четыре:

  • %CPU — доля одного ядра. 100% означает полностью занятое одно ядро, а не весь сервер. Многопоточный процесс легко покажет 380% на четырёхъядерной машине, и это нормально.
  • RES — резидентная память, реально занятая в RAM. Именно её, а не VIRT, надо смотреть при подозрении на утечку. VIRT включает отображённые файлы и зарезервированные диапазоны и почти всегда выглядит пугающе большим.
  • S — состояние процесса. R — работает или готов, S — спит, D — непрерываемый сон, то есть ждёт диск или сеть на уровне ядра, Z — зомби. Несколько процессов в D одновременно — почти всегда проблема хранилища, а не процессора.
  • Строка %Cpu(s) — распределение по типам: us (пользовательский код), sy (ядро), wa (ожидание ввода-вывода), st (steal — время, украденное гипервизором у виртуальной машины).

В top нажмите 1, чтобы развернуть строку CPU по ядрам: часто выясняется, что нагружено одно ядро из восьми, а значит проблема в однопоточном процессе, и апгрейд на 16 ядер ничего не изменит. htop удобнее для чтения, но по составу данных ничего принципиально нового не даёт.

Высокий st (единицы процентов и выше, устойчиво) на VPS означает, что гипервизор не отдаёт вам обещанные такты — это проблема соседей по хосту или переподписки тарифа, и внутри виртуальной машины она не лечится.

vmstat 1: колонки r, b, si, so и wa

Одна команда, которая разделяет три вида нагрузки. Первую строку вывода игнорируйте — это среднее с момента загрузки системы.

$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 6  0      0 152344  84120 2210436    0    0     0    28  912 1840 94  4  2  0  0
 5  0      0 151980  84120 2210436    0    0     0     0  880 1792 96  3  1  0  0
  • r — число процессов в очереди на выполнение. Устойчиво больше числа ядер — упёрлись в CPU.
  • b — число процессов в непрерываемом сне (ждут ввод-вывод). Больше нуля постоянно — упёрлись в диск.
  • si / so — страницы, читаемые из свопа и записываемые в своп, килобайт в секунду. Ненулевые значения в моменте — активный свопинг, самая болезненная разновидность тормозов.
  • wa — доля времени CPU в ожидании ввода-вывода. Высокий wa при низком us — процессор простаивает, ждёт диск.
  • cs — переключения контекста. Резкий рост при неизменной нагрузке говорит о слишком большом числе воркеров или потоков.

Три сценария читаются мгновенно:

Картина в vmstatЧто этоКуда копать
r больше числа ядер, wa около 0, us высокийНехватка CPUКакой процесс: ps aux --sort=-%cpu, PHP, компиляция, антивирус, крон
b больше 0, wa высокий, us низкийНехватка I/Oiostat -x 1, iotop, процессы в состоянии D
si и so ненулевые, free малСвопингНехватка RAM: free -h, кто съел — ps aux --sort=-%mem
sy высокий, cs огромный, us низкийНакладные расходы ядраСлишком много воркеров, шторм прерываний, сетевой флуд
st устойчиво больше нуляSteal на виртуалкеПереподписка хоста или лимит тарифа — вопрос к провайдеру

Память: free -h, page cache, своп и OOM killer

Самая частая ложная тревога: «свободной памяти почти нет». В Linux это норма. Ядро использует всю неиспользуемую память под page cache — кеш файлов на диске. Эта память отдаётся приложениям мгновенно, как только понадобится.

$ free -h
               total        used        free      shared  buff/cache   available
Mem:            7.7Gi       3.1Gi       210Mi       180Mi       4.4Gi       4.1Gi
Swap:           2.0Gi       512Mi       1.5Gi

Смотреть надо на available, а не на free. Available — это оценка ядра, сколько памяти реально можно выделить новому процессу без свопинга, с учётом освобождаемой части кеша. Здесь free = 210 МиБ выглядит страшно, а available = 4.1 ГиБ говорит, что памяти достаточно.

Тревожно, когда available падает до единиц процентов от total и одновременно в vmstat ненулевые si/so. Это уже свопинг: система вытесняет страницы приложений на диск и читает их обратно, каждое обращение к памяти превращается в дисковую операцию, и производительность падает на порядки.

Своп и swappiness

Параметр vm.swappiness задаёт, насколько охотно ядро вытесняет анонимные страницы вместо сброса page cache. Значение по умолчанию на большинстве дистрибутивов — 60.

cat /proc/sys/vm/swappiness
sudo sysctl -w vm.swappiness=10
# постоянно:
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf

# кто именно ушёл в своп (по процессам)
for f in /proc/*/status; do
  awk '/^Name:|^VmSwap:/{printf "%s ", $2} END{print ""}' "$f"
done | sort -k2 -h -r | head -15

Снижение swappiness до 10 разумно для серверов баз данных и веб-серверов: своп остаётся страховкой от OOM, но перестаёт использоваться «профилактически». Полное отключение свопа — плохая идея: без свопа ядро при нехватке памяти сразу зовёт OOM killer, и вместо замедления вы получаете убитый процесс.

OOM killer: как найти следы

Если процесс «просто исчез», а в логах приложения ничего нет — почти наверняка сработал OOM killer.

sudo dmesg -T | grep -i -E 'out of memory|killed process|oom-kill'
sudo journalctl -k --since "2 hours ago" | grep -i oom
sudo journalctl -u php-fpm --since today | grep -i -E 'exited|killed'

В строке ядра будет имя убитого процесса и его total-vm/rss на момент смерти. Это точная улика: вы знаете и что убили, и сколько оно занимало. Дальше вопрос в том, почему процесс вырос — утечка, слишком большой memory_limit в PHP при большом числе воркеров, или неудачный запрос, тянущий в память миллион строк.

Классическая ошибка на веб-сервере: pm.max_children в PHP-FPM выставлен «с запасом», а memory_limit — 512 МБ. При всплеске трафика сумма воркеров превышает RAM, начинается свопинг, потом приходит OOM killer и убивает базу данных как самый жирный процесс. Считайте max_children как доступная память, делённая на реальное среднее потребление воркера.

Схема памяти Linux: total, used, page cache и available, стрелка вытеснения страниц в своп
Page cache занимает всё свободное — это норма. Считать нужно available, а не free.

Диск: свободное место, иноды и удалённые открытые файлы

Забитый раздел даёт самые разнообразные симптомы: 502/503 от веб-сервера, отказ базы стартовать, «белый экран» PHP, невозможность записать сессию или лог. Проверка занимает пять секунд.

df -h
df -i
df -h /var /tmp /var/lib/mysql

df -h против df -i: почему «No space left on device» при свободном диске

Файловые системы семейства ext хранят метаданные файлов в иноды, число которых фиксируется при форматировании. Если приложение создало миллионы мелких файлов — кеш, сессии, очередь писем, временные файлы — иноды кончатся раньше места. Тогда df -h покажет 40% занятости, а любая запись будет падать с «No space left on device».

$ df -i /
Filesystem       Inodes   IUsed IFree IUse% Mounted on
/dev/vda1       3276800 3276794     6  100% /

Ищите каталог с миллионами файлов:

# сколько файлов в каждом подкаталоге верхнего уровня
sudo du -xh --max-depth=1 / | sort -h | tail -20
sudo find /var -xdev -type d -exec sh -c 'echo "$(ls -U "$1" | wc -l) $1"' _ {} \; 2>/dev/null | sort -rn | head

Типичные виновники: /var/lib/php/sessions, /var/spool/postfix, каталоги кеша CMS (bitrix/cache, wp-content/cache, var/cache), почтовые очереди, каталоги превью изображений.

Поиск того, что съело место

# сверху вниз, не выходя за пределы одной файловой системы
sudo du -xh --max-depth=1 / | sort -h
sudo du -xh --max-depth=1 /var | sort -h

# интерактивно — удобнее
sudo ncdu -x /

# журналы systemd умеют разрастаться
journalctl --disk-usage
sudo journalctl --vacuum-size=200M

Флаг -x обязателен: без него du уйдёт в /proc, сетевые монтирования и примонтированные тома контейнеров и даст бессмысленные числа.

Удалённые, но открытые файлы

Ситуация, которая ставит в тупик: du насчитал 20 ГБ, df показывает 90 ГБ занято. Значит, кто-то удалил большой файл, но процесс держит его дескриптор открытым — место освободится только после перезапуска процесса.

sudo lsof +L1
# или короче, только крупные:
sudo lsof -nP +L1 2>/dev/null | awk '$7 > 100000000'

Чаще всего это ротированный, но не переоткрытый лог: логи удалили руками вместо logrotate, а nginx или приложение продолжает писать в удалённый inode. Лечение — nginx -s reopen, systemctl reload сервиса или его перезапуск. И настроить logrotate, чтобы это не повторялось; подробнее — в материале о работе с логами.

Держите 15–20% свободного места на разделе с базой данных и на корне. На ext4 около 5% блоков зарезервировано под root, и когда обычные процессы уже не могут писать, система ещё загружается — это ваш запас на спасение, а не рабочее состояние.

Дисковый ввод-вывод: iostat -x 1, %util и await

Если vmstat показал ненулевую колонку b и высокий wa, переходите к iostat (пакет sysstat).

iostat -x 1
# только интересующее устройство
iostat -xd 1 vda

Ключевые колонки:

КолонкаЧто показываетКогда тревожно
r/s, w/sОпераций чтения и записи в секунду (IOPS)Упирается в лимит тарифа или диска
rkB/s, wkB/sПропускная способностьПостоянный потолок при низком IOPS — упор в полосу
r_await, w_awaitСреднее время ответа операции, мсДля SSD/NVMe — единицы мс норма, десятки уже плохо
aqu-szСредняя глубина очередиУстойчиво больше 1–2 — устройство не успевает
%utilДоля времени, когда устройство обслуживало запросы100% на HDD — насыщение; на NVMe число вводит в заблуждение

На NVMe и на сетевых дисках %util почти бесполезен: устройство параллельно обслуживает десятки очередей, и 100% не означает исчерпания. Ориентируйтесь на await и aqu-sz.

Кто именно делает ввод-вывод:

sudo iotop -oPa            # только активные, по процессам, с накоплением
pidstat -d 1               # то же без интерактивности
ps -eo state,pid,ppid,comm,wchan | awk '$1 ~ /^D/'

Частые причины всплеска I/O на веб-сервере: ночной бэкап или репликация, полное пересканирование антивируса, перестроение поискового индекса, запрос без индекса, который читает таблицу целиком, ротация и сжатие логов, и — на переподписанных VPS — соседи по хосту.

Сеть и соединения: ss -s и всплеск TIME-WAIT

Нагрузка бывает не в ресурсах, а в числе соединений. Симптом — сервер отвечает медленно или отдаёт ошибки, при этом CPU и диск свободны.

ss -s
ss -tan state time-wait | wc -l
ss -tan state established | wc -l
ss -ltn                       # что слушает и какие очереди
ss -tan state syn-recv | wc -l

В выводе ss -ltn смотрите колонки Recv-Q и Send-Q для слушающих сокетов: Recv-Q — текущая длина очереди принятых, но ещё не обработанных соединений, Send-Q — настроенный backlog. Если Recv-Q упирается в Send-Q, приложение не успевает принимать соединения, и часть клиентов получает таймауты или сброс.

Десятки тысяч сокетов в TIME-WAIT сами по себе не катастрофа: это нормальное состояние после закрытия соединения, оно уходит примерно за минуту. Проблема начинается, когда их число близко к диапазону локальных портов, и исходящие соединения (к базе, к API, к upstream) перестают устанавливаться.

cat /proc/sys/net/ipv4/ip_local_port_range
# лимит таблицы conntrack, если включён netfilter
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count
sudo dmesg -T | grep -i 'nf_conntrack: table full'

Правильное лечение всплеска TIME-WAIT — не крутить sysctl вслепую, а включить keep-alive между nginx и upstream, чтобы соединения переиспользовались. Практика описана в разборе тюнинга nginx. Если очередь соединений переполняется под наплывом — смотрите стратегии ограничения частоты запросов.

Кто конкретно грузит сервер: процессы, nginx, PHP-FPM, MySQL

Ресурс определён — теперь имя виновника.

ps aux --sort=-%cpu | head -15
ps aux --sort=-%mem | head -15
pidstat -u -p ALL 1 5 | sort -k8 -rn | head
systemd-cgtop                      # нагрузка по юнитам и контейнерам

nginx: найти медленные запросы

По умолчанию nginx не пишет время ответа в лог. Добавьте его — без этого искать нечего.

log_format timed '$remote_addr - $remote_user [$time_local] '
                 '"$request" $status $body_bytes_sent '
                 '"$http_referer" "$http_user_agent" '
                 'uct=$upstream_connect_time uht=$upstream_header_time '
                 'urt=$upstream_response_time rt=$request_time';

access_log /var/log/nginx/access.log timed;

После перезагрузки конфига (nginx -t && nginx -s reload) медленные URL находятся одной строкой:

# топ-20 самых долгих запросов
awk -F'rt=' '{print $2, $0}' /var/log/nginx/access.log | sort -rn | head -20

# сколько запросов в минуту сейчас
awk '{print $4}' /var/log/nginx/access.log | cut -d: -f2,3 | uniq -c | tail -10

PHP-FPM: slowlog и число воркеров

; в пуле, например /etc/php-fpm.d/www.conf
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 5s
request_terminate_timeout = 60s

pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 8
pm.max_requests = 500

Slowlog пишет полный стек PHP на момент превышения таймаута — это готовый ответ на вопрос «в какой функции висим». Смотреть статус пула:

sudo systemctl status php-fpm
# при включённом pm.status_path
curl -s http://127.0.0.1/status?full | head -40
grep -c 'pool www' /var/log/php-fpm/www-slow.log

Если в статусе постоянно виден listen queue больше нуля, воркеров не хватает. Но прежде чем повышать pm.max_children, посчитайте: воркеры × реальное потребление памяти воркером должно помещаться в RAM с запасом на базу и кеш. Иначе вы просто меняете медленный ответ на OOM. Про то, как это выглядит снаружи, — в разборах ошибки 502 и ошибки 503.

База данных: PROCESSLIST и медленные запросы

-- что выполняется прямо сейчас
SHOW FULL PROCESSLIST;

SELECT id, user, host, db, command, time, state, LEFT(info, 120) AS query
FROM information_schema.processlist
WHERE command <> 'Sleep'
ORDER BY time DESC
LIMIT 20;

-- включить журнал медленных запросов
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = 'ON';
# агрегировать журнал медленных запросов
sudo mysqldumpslow -s t -t 20 /var/log/mysql/slow.log

# посмотреть план проблемного запроса
mysql -e "EXPLAIN SELECT ...\G"

Один запрос без индекса на таблице в несколько миллионов строк способен положить сервер целиком: он читает таблицу с диска, вытесняет page cache, поднимает wa, и все остальные запросы начинают ждать. Это самая частая причина «внезапной» нагрузки на сайтах, которые годами работали нормально, — таблица просто доросла до размера, при котором полный перебор перестал быть дешёвым.

Слои веб-стека и точки замера: nginx, PHP-FPM, база данных, диск
В каждом слое — свой инструмент замера: время ответа nginx, slowlog PHP-FPM, PROCESSLIST базы.

Боты и парсеры или реальный трафик: разбор access.log

Прежде чем оптимизировать код, проверьте, за чей трафик вы платите. Разбор лога занимает минуту.

# топ IP по числу запросов
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# топ User-Agent
awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# топ URL
awk '{print $7}' /var/log/nginx/access.log | cut -d? -f1 | sort | uniq -c | sort -rn | head -20

# что делает конкретный IP
grep '^203.0.113.45 ' /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head

Признаки, по которым парсер отличается от людей:

  • Один IP или подсеть даёт непропорционально большую долю запросов — десятки в секунду без пауз.
  • Запросы идут строго последовательно по каталогу или по всем комбинациям параметров фильтра — комбинаторный взрыв на страницах со смарт-фильтром убивает сервер быстрее любого DDoS.
  • Нет запросов к статике: браузер тянет CSS, шрифты и картинки, парсер — только HTML.
  • Отсутствует или подделан Referer, User-Agent пустой, одинаковый на тысячи запросов или содержит имя HTTP-библиотеки.
  • Заявленный Googlebot приходит с адреса, который не подтверждается обратным DNS.
# проверка «настоящий ли это поисковый робот»
host 66.249.66.1
# в ответе должен быть домен googlebot.com или google.com,
# затем прямая проверка полученного имени:
host crawl-66-249-66-1.googlebot.com

Что с этим делать. Полезных роботов не блокируют — им ограничивают глубину: закрывают в robots.txt параметрические URL фильтров и сортировок, отдают корректные канонические ссылки, убирают бесконечные календари и пагинации. Вредным ставят ограничение частоты на уровне nginx:

limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
limit_conn_zone $binary_remote_addr zone=connperip:10m;

server {
    location / {
        limit_req  zone=perip burst=20 nodelay;
        limit_conn connperip 20;
        limit_req_status 429;
    }
}

Сначала выставляйте лимит в режиме наблюдения и смотрите, сколько живого трафика он бы задел: слишком жёсткое правило отрежет мобильных операторов с общим NAT-адресом. Подробный разбор порогов и алгоритмов — в статье про rate limiting.

Не блокируйте по User-Agent как основной мере: строка подделывается одной опцией в любой библиотеке. Ограничение частоты по адресу и по сессии работает против того, что реально стоит денег, — против количества запросов.

Симптом → быстрая проверка → вероятная причина → первое действие

СимптомБыстрая проверкаВероятная причинаПервое действие
Load высокий, wa около нуля, us 90%+ps aux --sort=-%cpu | headТяжёлый процесс: PHP, крон, импорт, антивирусНайти и остановить процесс, вынести задачу в очередь
Load высокий, wa высокий, us низкийiostat -x 1, iotop -oPaУпор в диск: бэкап, запрос без индекса, лимит IOPSОтложить фоновую задачу, найти запрос в slow log
Всё тормозит рывками, отклик плаваетvmstat 1 (si/so), free -hСвопинг из-за нехватки RAMСнизить число воркеров, найти утечку, добавить память
Процессы «исчезают» без ошибокdmesg -T | grep -i oomOOM killerПересчитать max_children и memory_limit
«No space left on device», диск свободенdf -iКончились инодыВычистить каталог с миллионами мелких файлов
df занято, du не находит объёмlsof +L1Удалённый, но открытый файлПерезапустить или reload держащего процесса
502/504 при свободных ресурсахss -ltn, статус пула PHP-FPMКончились воркеры или backlogПроверить upstream, увеличить воркеров в пределах RAM
Всплеск соединений, ресурсы свободныss -s, ss -tan state time-wait | wc -lНаплыв ботов или отсутствие keep-aliveРазобрать access.log, включить rate limit
Медленно только на одном ядре из восьмиtop, клавиша 1Однопоточная задачаПараллелить или профилировать код, а не добавлять ядра
st в vmstat устойчиво больше нуляvmstat 1Steal: переподписка хостаОбращение к провайдеру, смена тарифа или площадки

Быстрые меры и правильные: почему апгрейд без диагностики — самый дорогой путь

Быстрые меры нужны, чтобы сайт ожил прямо сейчас. Они не решают причину и требуют возврата к задаче.

  • Остановить фоновую задачу, которая совпала с пиком: импорт, бэкап, переиндексацию.
  • Включить или прогреть кеш страниц, отдавать анонимным пользователям статику из кеша.
  • Ограничить частоту запросов к тяжёлым URL на уровне nginx.
  • Временно отключить тяжёлый модуль или плагин, если пик совпал с его включением.
  • Убрать из крона всё, что не критично на ближайший час, и развести оставшееся по минутам, а не запускать «в ноль».

Правильные меры дают эффект надолго: индекс на таблицу, кеширование результата вместо повторного вычисления, вынос долгих операций в очередь, профилирование медленного кода, сжатие и отдача статики через CDN, оптимизация запросов. Практический разбор — в материалах о медленной загрузке сайта и оптимизации скорости.

Добавление ресурсов — законный вариант, но последний в списке. Если причина в однопоточном коде, ядра не помогут. Если причина в запросе без индекса, вы просто отложите проблему до следующего роста таблицы, заплатив за это ежемесячно. Апгрейд оправдан, когда диагностика показала честное исчерпание ресурса при уже оптимизированном приложении: например, устойчиво высокий await при упоре в лимит IOPS тарифа. Тогда переход на более быстрые диски или больший план у провайдера — например, у Selectel — решает задачу честно и предсказуемо.

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

Мониторинг, чтобы в следующий раз увидеть заранее

Разовая диагностика отвечает на вопрос «что сейчас». Она не отвечает на вопрос «когда началось» и «что изменилось». Для этого нужны исторические данные. Минимум, который окупается:

  • Сбор системных метрик с хранением хотя бы 30 дней: load, CPU по типам, память и своп, место и иноды, IOPS и await, число соединений.
  • Время ответа в логе веб-сервера — как показано выше. Без $request_time вы не отличите «сервер медленный» от «медленный один URL».
  • Слой приложения: медленные запросы к базе, счётчик ошибок 5xx, длина очередей.
  • Алерты на симптомы, а не на пороги ресурсов: рост доли 5xx и рост времени ответа важнее, чем «CPU выше 80%». Логика — в разборе золотых сигналов мониторинга.
  • Централизованные логи с ротацией — иначе разбор инцидента упрётся в то, что нужные строки уже удалены; см. практики работы с логами.
График времени ответа и доли ошибок во времени с отмеченным началом деградации до пика нагрузки
История метрик отвечает на главный вопрос инцидента: что изменилось и когда это началось.

Как проверить снаружи

Диагностика изнутри показывает ресурсы, но не показывает, что видит пользователь. Внешний замер закрывает этот пробел и заодно отвечает на вопрос, действительно ли проблема на сервере.

  • Замерить время ответа и TTFB. Инструмент проверки скорости сайта показывает время до первого байта и полное время загрузки. Высокий TTFB при быстрой отдаче остальной страницы — это ровно то, что вы только что искали внутри: сервер долго думает.
  • Зафиксировать падения и деградацию. Мониторинг доступности даёт историю: когда началось, как долго длилось, повторяется ли по расписанию. Регулярные пики по часам — почти всегда крон или бэкап.
  • Отделить свою аварию от чужой. Раздел сбоев и инцидентов помогает понять, локальная у вас проблема или у провайдера, CDN либо внешнего API, от которого вы зависите.
  • Проверить, не связаны ли всплески с ошибками страниц. Массовые 404 и цепочки редиректов заставляют роботов ходить кругами и создают лишнюю нагрузку — поиск битых ссылок находит такие маршруты.

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

Частые вопросы

Какая нагрузка на сервер считается нормальной?

Универсального числа нет. Ориентир: load average, делённый на число ядер, устойчиво ниже 0,7 — запас есть; около 1 — работа на пределе; выше 2 — очередь растёт, отклик деградирует. При этом высокий load при нулевом wa и низком времени ответа сайта проблемой не является: сервер занят, но справляется.

Как посмотреть нагрузку на сервер Linux одной командой?

vmstat 1 5 даёт больше всего информации за один вызов: очередь на CPU, блокированные процессы, своп, ввод-вывод и распределение процессорного времени. Если из системы доступен только top, нажмите 1 для разбивки по ядрам и смотрите строку %Cpu(s) и колонку состояния S.

Как проверить свободное место на диске в Linux?

df -h покажет место, df -i — иноды. Проверять нужно обе команды: «диск полон» при видимо свободном месте — это почти всегда кончившиеся иноды. Найти, что занимает объём, помогает du -xh --max-depth=1 / или интерактивный ncdu -x /.

Стоит ли отключать своп на веб-сервере?

Нет. Своп — не причина тормозов, а индикатор нехватки памяти. Без свопа при исчерпании RAM ядро сразу вызывает OOM killer и убивает процесс — обычно самый крупный, то есть базу данных. Разумнее оставить небольшой своп и снизить vm.swappiness до 10.

Как понять, что нагрузку создают боты, а не пользователи?

Разберите access.log: посчитайте запросы по IP и по User-Agent, посмотрите долю обращений к статике. Живой браузер запрашивает CSS, шрифты и изображения, парсер — только HTML. Последовательный обход всех комбинаций параметров фильтра и десятки запросов в секунду с одного адреса — надёжный признак автоматики.

Поможет ли добавление процессоров и памяти?

Только если диагностика показала честное исчерпание именно этого ресурса. При однопоточной задаче лишние ядра не используются, при запросе без индекса память лишь отодвигает проблему. Апгрейд без диагностики — самый дорогой способ отложить решение: он оплачивается каждый месяц.

Чеклист: 15 минут на поиск причины

  • uptime и nproc — нормализовать load на число ядер, оценить тренд по трём числам.
  • vmstat 1 — определить слой: r (CPU), b и wa (диск), si/so (своп), st (гипервизор).
  • free -h — смотреть available, а не free; проверить, растёт ли использование свопа.
  • dmesg -T | grep -i oom — проверить, не убивал ли OOM killer процессы за последние часы.
  • df -h и обязательно df -i — место и иноды на всех разделах.
  • du -xh --max-depth=1 / или ncdu -x /, при расхождении с dflsof +L1.
  • iostat -x 1 — await и aqu-sz; iotop -oPa — кто именно пишет и читает.
  • ss -s и ss -ltn — число соединений, переполнение очереди приёма.
  • ps aux --sort=-%cpu и --sort=-%mem — назвать процесс по имени.
  • Логи: время ответа nginx, slowlog PHP-FPM, SHOW FULL PROCESSLIST и журнал медленных запросов базы.
  • access.log: топ IP, топ User-Agent, доля запросов к статике — отделить ботов от людей.
  • Внешний замер: скорость, история в мониторинге, контекст в сбоях.
  • Записать одно изменение, замерить эффект, только потом делать следующее.

Проверьте ваш сайт прямо сейчас

Следить за сайтом непрерывно →
Другие статьи: Мониторинг
Мониторинг
Проектирование health check эндпоинтов для веб-сервисов
16.03.2026 · 381 просм.
Мониторинг
Лучшие практики алертинга для мониторинга сайтов
14.03.2026 · 351 просм.
Мониторинг
ТОП-10 сервисов мониторинга сайтов 2026: честное сравнение функций и цен
01.04.2026 · 315 просм.
Мониторинг
Uptime сайта и SLA: что означают 99.9% и как считать доступность
13.03.2026 · 303 просм.