Как диагностировать тормоза Linux-сервера: чек-лист сисадмина
· 17 мин чтения

Как диагностировать тормоза Linux-сервера: чек-лист сисадмина

Как диагностировать тормоза Linux-сервера: чек-лист сисадмина

«Сервер тормозит» — знакомо, правда? Для нас, в ITFresh, это самая частая и, пожалуй, самая расплывчатая жалоба. За 15 лет работы мы, конечно, научились справляться. Мы разработали свой чёткий алгоритм: от первого SSH-подключения до постановки точного диагноза проходит всего 20-30 минут. В этом материале я поделюсь нашим пошаговым чек-листом. Там будут конкретные команды, подробные объяснения их вывода, и, конечно, типичные проблемы, с которыми мы постоянно сталкиваемся на практике.

Первые 60 секунд: общая картина

Нам звонят, кричат: «У нас всё жутко медленно!». И что, мы сразу бросаемся в дебри сложных профилировщиков? Вовсе нет. Мы первым делом запускаем две простые команды. И вот парадокс: буквально за минуту эти две простейшие команды показывают до 80% всей картины происходящего на сервере. Это не наша придумка, это подход Брендана Грегга. И мы под ним подписываемся каждой буквой, потому что он работает.

uptime
dmesg -T | tail -30
vmstat 1 5
mpstat -P ALL 1 5
pidstat 1 5
iostat -xz 1 5
free -m
sar -n DEV 1 5
sar -n TCP,ETCP 1 5
top -b -n 1 | head -25

Эти десять команд за 60 секунд дают полный срез по CPU, памяти, диску, сети и активным процессам. Я держу их в скрипте /usr/local/bin/perf60 на каждом сервере, который сопровождаю.

На что смотрю в первую очередь:

CPU: горит ли процессор

Если команда `vmstat` выдаёт высокое значение `us%` (user) или `sy%` (system), а вот `wa%` (iowait) при этом остаётся низким — поздравляю, мы нашли виновника. Это центральный процессор, CPU. Теперь нам нужно выяснить, какие процессы, а точнее, какие функции внутри них так жадно «съедают» все доступные такты.

Шаг 1. top или htop. Сортировка по %CPU, видим топ-5 процессов.

htop -d 5 -s PERCENT_CPU

Итак, что видим? Если в топе один-единственный процесс съедает 100-400% CPU (да, это значит, он полностью грузит 1-4 ядра), считайте, проблема локализована. А если процессорное время размазано тонким слоем между десятками процессов? Тогда это системная проблема. Здесь уже придётся покопаться поглубже, искать причину именно в общей нагрузке.

Шаг 2. mpstat по ядрам. Иногда «загрузка 25%» на 4-ядерной системе означает, что одно ядро забито на 100%, а остальные простаивают. Это классика для однопоточного приложения.

mpstat -P ALL 1 10

Смотрим на `top` или `htop`: если `us%` на одном ядре приближается к 100%, а на остальных ядрах практически ноль — bingo! Это типичная картина. Ваше приложение однопоточное и просто упёрлось в производительность одного ядра. Какие есть варианты? Либо пробовать его параллелить, если, конечно, это возможно. Либо искать процессор с гораздо большей одноядерной производительностью. Выбор за вами.

Шаг 3. perf top для глубокого анализа.

perf top -p $(pgrep -d, java)
# или для всей системы
perf top -g

Теперь мы чётко видим, в каких функциях процессор просто сгорает. На нашей практике часто оказывается, что приложение буквально застряло в каком-нибудь прожорливом regex-движке, или же причина в неоптимальном сборщике мусора (GC). Помню, у одного нашего клиента, совсем недавно, выяснилось: 60% ресурсов PostgreSQL уходило исключительно на парсинг одного и того же, постоянно повторяющегося SQL-запроса. Простая штука — `prepared statement` — решила проблему влёт.

Шаг 4. Если приложение чужое или закрытое — strace и ltrace.

sudo strace -c -p $(pgrep -f myapp)
# Останавливаем через 10-15 секунд Ctrl+C, видим распределение syscalls
sudo ltrace -f -c ./myapp
# Покажет вызовы библиотечных функций

Запустили `strace -c` и видите, что там доминируют вызовы `read/write` на крошечных блоках — буквально 4-32 байта? Это прямой сигнал: приложение тратит уйму времени на системные вызовы (тот самый `syscall overhead`). Что делать? Нужно либо срочно буферизовать ввод/вывод (I/O), либо, если архитектура позволяет, переходить на современный `io_uring`.

Память: своп, OOM, утечки

Ах, память! Вот уж что может подкинуть сюрпризов. Пожалуй, это самая коварная подсистема из всех. Очень часто, когда мы слышим то самое «сервер тормозит», оказывается, что система уже вовсю занялась активной подкачкой. А это что значит? Каждый ваш запрос, вместо быстрой работы с RAM, превращается в настоящую, медленную дисковую операцию. Приятного мало, согласитесь?

Шаг 1. free -h и понимание буферов.

free -h
              total        used        free      shared  buff/cache   available
Mem:           31Gi        18Gi       1.2Gi       512Mi        12Gi         12Gi
Swap:         4.0Gi       2.1Gi       1.9Gi

Главная цифра — available. Это сколько памяти можно реально выделить новому процессу с учётом возможности освободить кеши. Если available меньше 10% от total — пора смотреть детально. Если в swap используется больше 1 ГБ и swap-in/out активный — уже проблема.

Шаг 2. vmstat для динамики свопа.

vmstat 1 30
# Смотрим колонки si (swap in) и so (swap out)

Видите, что показатели `si/so` стабильно выше нуля? Значит, система вовсю своппит. А теперь представьте: каждая `swap-in` операция — это, по сути, чтение с диска. Разве можно сравнивать скорость диска с оперативной памятью? Это медленнее в десятки тысяч раз! Если под `swap` у вас SSD, ну, ещё куда ни шло, терпимо. Но если HDD… Ох, это уже настоящая катастрофа для производительности.

Шаг 3. Кто потребляет память — smem.

sudo apt install smem
sudo smem -k -s pss -r | head -20

В отличие от обычной команды `ps`, у `smem` есть свой козырь: он показывает `PSS` (Proportional Set Size). Что это даёт? Это реальное потребление памяти, но уже с учётом разделяемых библиотек. Когда речь идёт о приложениях, которые форкают кучу процессов, например, `nginx workers`, `PSS` даёт самую что ни на есть честную и неискажённую картину потребления. Нам это очень помогает.

Шаг 4. Утечки памяти — /proc/PID/smaps_rollup.

cat /proc/$(pgrep -f myapp)/smaps_rollup
# Снимаем дважды с интервалом в час, сравниваем Rss и Pss

Видите, что показатель `RSS` растёт линейно, хотя нагрузка стабильна? Поздравляю, у вас утечка памяти. И это большая проблема. А дальше что? В зависимости от языка, берём инструменты: `valgrind` для C/C++, `pprof` для Go, `py-spy` для Python. Как-то раз, на нашей практике, у одного клиента мы нашли интересную утечку в самописном экспортере метрик. Оказалось, каждый запрос к `/metrics` попросту забывал закрыть соединение к базе данных. Результат? Через сутки такой работы система «съедала» лишние 8 ГБ памяти.

Шаг 5. OOM-killer — анализ по dmesg.

dmesg -T | grep -i 'killed process\|oom-killer'
# Пример вывода:
# [Thu Apr 17 03:14:22 2026] Out of memory: Killed process 12345 (java) total-vm:8388608kB...

Что делать, если `OOM-killer` добрался до критичного процесса и прихлопнул его? У нас два пути. Первый: просто докупить и увеличить оперативную память (RAM). Второй, и мы его обычно предпочитаем: ограничить аппетиты других, менее критичных процессов. Как это сделать? Например, через `systemd`:

# /etc/systemd/system/myapp.service.d/limits.conf
[Service]
MemoryHigh=4G
MemoryMax=6G
MemorySwapMax=0
OOMScoreAdjust=-500

Параметр `OOMScoreAdjust=-500` — это такой наш сигнал ядру. Мы как бы говорим ему: «Дружище, если уж придётся кого-то убивать, оставь этот процесс на самый-самый последний момент!». Очень полезно для по-настоящему критичных сервисов, вроде той же базы данных PostgreSQL.

Диск: IOPS, latency, очереди

А вот когда речь заходит об обычных офисных серверах, тут, по нашей практике, диск — это просто рекордсмен по званию «узкое место». Скажу вам честно: если вы поставили `RAID 5` на простых `SATA`-дисках, да ещё и под нагрузкой той же `1С`… это, поверьте, верный путь. Верный способ превратить даже самый мощный и современный сервер в настоящий кисель. Просто не сможет он работать.

Шаг 1. iostat -x для расширенной статистики.

iostat -xz 1 10
# Ключевые столбцы:
#   r/s, w/s — IOPS чтения/записи
#   rkB/s, wkB/s — пропускная способность
#   await — средняя задержка операции в мс
#   %util — загрузка устройства

Есть свои нормы, конечно. Для SSD-дисков: `%util` до 80% при `await` менее 5 миллисекунд — это нормально. Для старых добрых HDD: `%util` до 70% при `await` менее 20 миллисекунд. Но что если вы видите `await` больше 50 мс, или `%util` постоянно держится на отметке 95% и выше? Всё просто: ваш диск перегружен, и очень сильно. Если такой скачок `await` случился во время бэкапа или `ребилда RAID` — ну, тут понятно, это объяснимо. Но если это происходит постоянно, без видимых причин… Тогда у вас два пути: либо срочно ускорять дисковую подсистему, либо грамотно разносить нагрузку.

Шаг 2. Кто грузит диск — iotop.

sudo iotop -oPa
# -o только активные процессы
# -P только процессы (не потоки)
# -a накопленные значения

Иногда выясняется, что 70% дисковой нагрузки — это journald, который пишет логи в синхронном режиме. Лечится переключением в asynchronous через SyncIntervalSec=5min в /etc/systemd/journald.conf.

Шаг 3. Глубокая трассировка дисковых операций — eBPF.

sudo apt install bpfcc-tools
sudo biolatency-bpfcc 5 1
# Гистограмма задержек дисковых операций за 5 секунд
sudo biosnoop-bpfcc
# Live-выдача каждой дисковой операции: PID, диск, тип, размер, latency

Вот почему biolatency так важен: он покажет распределение задержек. Представьте, если видите заметный «хвост» в районе 50-100 мс – это верный признак периодических тормозов. Такие проблемы обычно усредняются и остаются незамеченными для обычного iostat. На нашей практике был случай: у клиента в RAID 6 так нашли проблемный диск. Сам iostat по массиву показывал идеальную картину, но biosnoop обнаружил, что один-единственный диск выдаёт задержки на запись за 200 миллисекунд. Вот где собака зарыта!

Шаг 4. SMART-статус и износ.

sudo smartctl -a /dev/sda
# Смотрим:
#   ID 5 — Reallocated_Sector_Ct (>0 — диск умирает)
#   ID 197 — Current_Pending_Sector (>0 — плохие сектора)
#   ID 231 — SSD_Life_Left (на SSD, должно быть >10%)
#   ID 241 — Total_LBAs_Written (на SSD — расход ресурса записи)

Мы обязательно ведём историю по этим критически важным показателям в Zabbix. При любом росте reallocated sectors сразу настроен алерт. Знаете, это часто даёт нам ценную фору — бывает, что и неделю, а то и две, до того, как диск полностью выйдет из строя. Это позволяет подготовиться и минимизировать риски.

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

Обычно, когда что-то не так с сетью, вы слышите чёткие жалобы: '1С отвалилась!', 'Сайт не грузится!' Сетевые проблемы редко проявляются просто как 'всё стало медленным'. Но что делать, если симптомы какие-то неясные, непонятные, а общее ощущение, что 'что-то не так'? В таких случаях я всегда, просто обязательно, проверяю и сетевое соединение.

Шаг 1. ss для активных соединений.

ss -tunap | head -20
# Видим все TCP/UDP соединения с PID процессов

ss -s
# Сводка: количество соединений по типам, состояниям

Видите тысячи TIME_WAIT соединений? Это чёткий сигнал: ваше приложение плохо переиспользует TCP-сессии. А если ESTABLISHED connections зашкаливают до десятков тысяч, то, скорее всего, у вас утечка соединений. Мы в ITFresh с такими ситуациями сталкивались не раз. И что интересно – в обоих случаях решение было одно: просто нужно было правильно настроить пул соединений прямо в приложении.

Шаг 2. sar -n DEV для трафика интерфейсов.

sar -n DEV 1 5
# Колонки:
#   rxpck/s, txpck/s — пакеты в секунду
#   rxkB/s, txkB/s — пропускная способность
#   rxerr/s, txerr/s — ошибки

Если видите, что rxerr или txerr вдруг больше нуля, это прямое указание на проблемы с физическим уровнем. Причины могут быть разными: банальный бракованный кабель, сбоящая сетевая карта (NIC) или рассогласованный дуплекс. А вот ethtool — ваш лучший друг, чтобы быстро увидеть все детали и понять, где именно загвоздка.

ethtool eth0
# Speed, Duplex, Auto-negotiation
sudo ethtool -S eth0 | grep -i error
# Hardware error counters: rx_crc_errors, tx_aborted_errors

Ох, эти rx_crc_errors! Особенно они коварны на гигабитных линках, проложенных по UTP кабелю. Знаете, бывает так, что даже сертифицированный кабель, который прекрасно работает на своей максимальной скорости, на длинных дистанциях начинает 'сыпать' ошибками. Что же делать? Тут есть два рабочих варианта: либо меняем кабель на новый, либо просто принудительно устанавливаем скорость 100 Мбит. Часто это спасает ситуацию.

sudo ethtool -s eth0 speed 100 duplex full autoneg off

Шаг 3. tcpdump для конкретных проблем.

sudo tcpdump -i any -nn -w /tmp/cap.pcap host 192.168.1.10 and port 5432
# Захват трафика к PostgreSQL с конкретного клиента
# Открываем в Wireshark, смотрим RTT, retransmissions, window size

Заметили много TCP retransmission в Wireshark? Значит, пакеты где-то теряются по дороге. А если видите 'zero window', это сигнал, что получатель просто не успевает их обрабатывать. Всё просто, но диагностика бывает непростой.

Шаг 4. Современная альтернатива — tcptracer-bpfcc и tcpconnect-bpfcc.

sudo tcpconnect-bpfcc
# Live-список новых TCP-соединений с указанием процесса
sudo tcpretrans-bpfcc
# Live-список retransmission с PID и временем

С помощью этого инструмента мы теперь можем в реальном времени отслеживать, какой именно процесс, куда и зачем открывает соединения. Более того, сразу видно, где, в каком месте, начинают теряться пакеты! Согласитесь, это очень удобно. Раньше, до появления eBPF, подобные задачи требовали танцев с бубном и жутко сложных настроек в systemtap. Прогресс налицо!

Кейс из практики: 1С-сервер тормозил по вечерам

Давайте я расскажу вам про один реальный случай, который у нас был. Дело было в январе 2026 года. У нашего клиента — обычный офис на 40 рабочих мест, а сервер 1С крутится на Ubuntu с PostgreSQL 16. И вот на что они жаловались: ровно с 16:30 до 18:00 проведение документов дико тормозило. Часам к 17:30 интерфейс вообще 'умирал' и переставал отвечать. А потом, словно по волшебству, к 18:30 всё, как ни в чём не бывало, налаживалось! Ну разве не загадка?

Что я делал по шагам:

  1. 16:35. Подключился по SSH. uptime показал load average 18.5/12.3/8.2 при 8 ядрах. Перегрузка свежая, нарастает.
  2. 16:36. top: PostgreSQL съедает 600% CPU (6 ядер из 8), 1С — 200% (2 ядра). Процессов postgres много, видимо, активные сессии.
  3. 16:38. mpstat -P ALL: загрузка размазана, не однопоточная проблема.
  4. 16:40. iostat -x: %util диска 95%, await 80 мс, разрывы под бэкап в 17:00. Странно, бэкап ещё не запустился.
  5. 16:42. iotop -oPa: pg_dump потребляет 250 МБ/с чтения. Кто-то запустил дамп в рабочее время!
  6. 16:44. ps aux | grep pg_dump: дамп запустил Cron-задание клиента, которое они сами поставили месяц назад «для подстраховки».
  7. 16:45. Убил pg_dump, нагрузка на диск упала за минуту, тормоза в 1С прекратились через 3 минуты.

Диагноз, как это часто бывает, оказался до банальности прост: дублирующий бэкап почему-то накладывался прямо на пиковую нагрузку от пользователей. Что мы сделали? Всё просто: убрали один лишний cron-запуск, и теперь на сервере остался только наш надёжный ночной бэкап через Borg. Но этого мало! Чтобы подобная ситуация больше никогда не повторилась, я специально повесил Zabbix-триггер. Он сработает моментально, если вдруг pg_dump решит запуститься в рабочее время.

Вся диагностика заняла всего 12 минут! Представляете? Если бы мы не использовали такой чёткий, структурированный подход, мы бы, скорее всего, потеряли минимум полдня на бесконечные 'а давайте сначала перезагрузим сервер', 'может, сеть?', 'а проверьте там...'.

Профилактика: метрики в Zabbix

Реактивная диагностика, конечно, важна, но я всегда убеждён: проактивный подход — вот что по-настоящему спасает. Именно поэтому мы на каждом сервере собираем минимум три десятка ключевых метрик в Zabbix. Причём, не просто собираем, а с разной частотой — в зависимости от критичности показателя.

ПодсистемаМетрикаТриггер
CPUload average 5min, %iowait, %stealload > 2× ядер за 15 мин; iowait > 30%
Памятьavailable, swap used, OOM eventsavailable < 10%; swap > 1 ГБ; любой OOM
Диск%util, await, IOPS, free spaceutil > 90% за 10 мин; await > 50 мс
Сетьtraffic, errors, retransmitserrors > 0; retrans > 1% от трафика
SMARTreallocated, pending, life_leftreallocated > 0; life_left < 10%
Сервисыprocess count, port listen, response timeсервис упал; LCP > 3 сек; RPS < baseline-30%

Все важные алерты, конечно, моментально летят прямиком в Telegram нашему дежурному инженеру. А вот тренды мы храним целых 90 дней. Этого, кстати, более чем достаточно, чтобы потом спокойно, без спешки, сравнить: 'Что было до изменений?' и 'Как стало после?' Очень помогает в анализе.

Чек-лист, который я держу под рукой

Нужна молниеносная диагностика? Вот вам наша 'шпаргалка' — краткая карточка для быстрого подключения к любому проблемному серверу:

  1. uptime — состояние нагрузки.
  2. dmesg -T | tail -50 — что говорит ядро.
  3. vmstat 1 5 — общий обзор r/b/si/so/wa.
  4. top -b -n 1 | head -20 — топ процессов.
  5. free -h — память.
  6. iostat -xz 1 5 — диски.
  7. sar -n DEV 1 5 — сеть.
  8. ss -s — сводка соединений.
  9. journalctl -p err -n 100 — критичные ошибки сервисов.
  10. df -h && df -i — место и inodes.

Всего за 5-7 минут эти десять команд дадут мне до 90% всей нужной информации для первичной диагностики. Это просто магия! А вот дальше уже, в зависимости от того, какая подсистема 'всплыла' как виновник, мы начинаем углубляться в более мощные инструменты: perf, eBPF или tcpdump.

Что не работает: антипаттерны диагностики

За годы практики в IT мы, в ITFresh, чего только не видели. Но, к сожалению, есть ошибки, которые повторяются у коллег снова и снова.

«Перезагрузим — посмотрим». Перезагрузка сбрасывает контекст, и причина теряется. Сначала собрать sosreport или sar history, потом перезагружать (если уж очень нужно).

«У нас памяти всё хорошо, видишь — used маленький». Используется значение used вместо available. На современных Linux буферы и кеш считаются как used, но фактически освобождаются по требованию. Смотреть надо available.

«Я просто увеличил CPU/RAM, должно помочь». Без понимания root cause увеличение ресурсов лишь отодвигает проблему. У одного клиента трижды наращивали vRAM на сервере 1С, прежде чем нашли утечку в стороннем расширении конфигурации.

«Логи смотреть не буду, там много». Большинство симптомов уже описано в логах. journalctl с фильтром по приоритету занимает 30 секунд:

journalctl --since "1 hour ago" -p err
journalctl -u myservice.service --since "30 minutes ago"

FAQ

С чего начать диагностику тормозов сервера?
С Load Average (uptime), top или htop. За 30 секунд понятно, какая подсистема перегружена: CPU, диск или памяти не хватает. Дальше углубляемся в детали через iostat, perf и eBPF.

Что такое eBPF и зачем он сисадмину?
eBPF — это виртуальная машина внутри ядра Linux, которая позволяет запускать безопасные программы трассировки. Утилиты bcc-tools и bpftrace показывают, что именно делают процессы: какие syscalls, файловые операции, сетевые соединения. Без eBPF многие вещи раньше требовали пересборки ядра.

Как понять, что узкое место — диск, а не CPU?
Смотрим столбец %iowait в top или vmstat. Если %iowait > 20% при низкой загрузке CPU — упёрлись в диск. Подтверждаем через iostat -x: если %util > 90% и await > 50ms — диск перегружен.

Что делать при OOM-killer на проде?
Сначала смотрим dmesg для понимания, кого убило ядро. Затем настраиваем cgroups через systemd-slice для критичных сервисов с MemoryHigh и MemoryMax. Параллельно ищем утечку через smem и /proc/PID/smaps_rollup.

Сколько стоит аудит производительности Linux-сервера у АйТи Фреш?
Базовый аудит одного сервера — от 25 тысяч рублей: 1-2 дня снятия метрик, анализ, отчёт с конкретными рекомендациями. Если требуется проактивный мониторинг — включаем в абонентский договор.

Тормозит ваш сервер? Поможем разобраться

Ваш Linux-сервер еле дышит? Если вы понятия не имеете, что с ним происходит, не мучайтесь! Просто закажите экспресс-аудит у нас, в ITFresh. За 1-2 дня мы оперативно снимем все нужные метрики, точно найдём то самое «узкое место» и, конечно, дадим вам не просто диагноз, а чёткий план по оптимизации. Готовы действовать? Оставьте заявку на itfresh.ru или напишите нам: 7296241@gmail.com. И, что приятно, если после аудита решите взять нас на полное сопровождение, стоимость аудита мы зачтём.

Семёнов Е.С., технический директор АйТи Фреш. 15+ лет в IT-аутсорсинге для бизнеса.

Подпишитесь на рассылку ITfresh

Надоело искать ответы в гугле? Мы предлагаем кое-что получше. Раз в неделю мы выпускаем практические гайды для руководителей IT и сисадминов. Внутри только самое важное и актуальное: от безопасности и 1С до миграций и резервных копий. И, конечно, куча полезных лайфхаков, опробованных нами в реальных проектах.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.