Когда сервер «тормозит», ощущения мало: нужно понять, где именно узкое место — процессор, диск, сеть или память. В Linux есть набор инструментов профилирования: perf, pidstat, iostat, vmstat. Разберём, как ими пользоваться по порядку, чтобы за несколько минут сузить круг поиска.

Первый шаг: общая картина

Начинайте с top/htop и vmstat: они сразу показывают, перегружена ли CPU, ждёт ли система ввода-вывода или упирается в память.

# сводка по системе за 5 секунд
vmstat 1 5
# поля: r — в очереди, b — ждущие I/O, si/so — своп, wa — ожидание диска
# нагрузка по ядрам
mpstat -P ALL 1 5
# топ процессов по CPU
ps -eo pid,user,pcpu,pmem,comm --sort=-pcpu | head -12

Значение wa выше единицы и большой b указывают на диск. Большое r с высоким us — на CPU.

I/O: iostat и поиск виновника

Диск — самая частая причина «зависаний». Смотрите не только %util, но и латентность: при высокой она читается в %await.

# установить
sudo apt install sysstat
# I/O по устройствам
iostat -xz 1 5
# топ процессов по I/O
pidstat -d 1 5
# кто именно пишет
sudo iotop -oPa 2>/dev/null | head -20

Если %util у SSD около 100%, это ещё не перегрузка — SSD параллельны. Ориентируйтесь на await и достижимую пропускную способность.

perf: профилирование CPU

perf собирает статистику процессора и показывает, где тратится время. Он требует понимания, но даёт конкретные функции, а не общие слова.

# установить (нужен debug-символы для полной картины)
sudo apt install linux-perf
# сводка по процессу (PID подставьте свой)
perf stat -p PID sleep 10
# профиль горячих функций
perf record -g -p PID -- sleep 10
perf report --stdio | head -40
# включить запись по юниту (пример)
perf top -C 0-3 2>/dev/null | head -20

Без debug-символов отчёт покажет адреса вместо имён. Установите пакет linux-image-...-dbgsym или используйте perf report с подсказками по низкоуровневым функциям.

Память: где утечка

# потребление и своп
free -h
# давление на память
cat /proc/pressure/memory
# топ по RSS
ps -eo pid,rss,comm --sort=-rss | head -12
# динамика процесса
pidstat -r 1 5

Растущий RSS при простой нагрузке — признак утечки. Смотрите динамику десятки секунд, а не одиночный снимок.

Сеть: задержка и потери

# состояние соединений
ss -tan | awk 'END{print NR" соединений"}'
# ошибки и потери на интерфейсе
ip -s link show eth0
netstat -s 2>/dev/null | grep -iE "retrans|drop" | head
# задержка до хоста
mtr -rwc 30 example.com | tail -12

Ретрансмиссии TCP растут при перегрузке сети или буферов — проверьте ss -tm и значения net.core.wmem.

Собираем картину вместе

  1. vmstat — CPU, диск, память, своп.
  2. pidstat -d и pidstat -r — кто нагружает.
  3. iostat -xz — латентность диска.
  4. perf record — горячие функции.
  5. Сравните с моментом, когда всё работало хорошо.
# сохранить срез для отчёта
mkdir -p ~/perf && cd ~/perf
vmstat 1 5 > vmstat.txt
iostat -xz 1 5 > iostat.txt
pidstat -dur 1 5 > pidstat.txt
perf record -g -- sleep 10 2>/dev/null

Частые ошибки измерений

  • Профилирование на тестовом стенде без реальной нагрузки.
  • Одиночный снимок вместо динамики.
  • Игнорирование времени самого инструмента: perf сам потребляет CPU.
  • Сравнение чисел разных конфигураций без фиксации настроек.
# зафиксировать условия теста
uname -r > env.txt; lscpu >> env.txt; free -h >> env.txt

Воспроизводимые измерения

Цифры полезны только в сравнении: зафиксируйте версию ядра, настройки и нагрузку до и после изменения. Иначе «стало быстрее» превращается в субъективное впечатление.

# условия теста
uname -r > bench/env.txt
lscpu >> bench/env.txt
free -h >> bench/env.txt
cat /proc/cmdline >> bench/env.txt
# один и тот же тест до/после
fio --name=bench --rw=randread --size=1G --runtime=60 --time_based | tee -a bench/io.txt

Прогоняйте тест несколько раз подряд: первое измерение почти всегда отличается из-за разогрева кэшей и планировщика. Берите медиану, а не максимум.

Профилирование внутри контейнеров

В контейнере perf видит процессы хоста, но сбор символов может блокироваться из-за изоляции. Запускайте профилирование на хосте с указанием PID.

# найти PID контейнера на хосте
docker inspect -f '{{.State.Pid}}' mycontainer 2>/dev/null
# профилировать процесс хоста
perf record -g -p PID -- sleep 10
# ограничения ресурсов контейнера
docker stats --no-stream 2>/dev/null | head

Если сервис работает под systemd, удобнее профилировать юнит: perf record -u nginx.service — это избавляет от поиска PID.

Когда инструменты не помогают

Бывает, что нагрузка уходит в ожидание, которое не видно ни в top, ни в iostat: блокировки базы данных, очереди в приложении, задержки внешних API. В этом случае смотрите логи приложения и трассируйте вызовы через strace -c -p PID или eBPF-инструменты вроде bpftrace.

# счётчик системных вызовов процесса
sudo strace -c -p PID 2>/dev/null &
sleep 10 && kill %1 2>/dev/null
# проверить, есть ли bpftrace
which bpftrace 2>/dev/null || echo "установите из репозитория"

Собирайте данные из нескольких источников и сопоставляйте по времени: только тогда картинка становится полной.

Итог

Поиск узкого места — последовательность: vmstat для выбора направления, pidstat/iostat для виновника, perf для конкретных функций. Фиксируйте условия и динамику, а не одиночные значения: так решение принимается на данных, а не на ощущениях.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте