Перейти к содержанию

Диагностика высокой нагрузки CPU и памяти

«Сервер тормозит» — это не диагноз, а отправная точка. Эта статья — о стандартном наборе инструментов, позволяющем узнать, что именно потребляет CPU, память или I/O, по порядку, а не угадывая.

Как это устроено

Начните с top (или htop), но читайте его правильно

$ top -b -n 1 | head -15
top - 14:22:01 up 12 days,  3:41,  2 users,  load average: 2.14, 1.98, 1.76
Tasks: 210 total,   2 running, 208 sleeping,   0 stopped,   0 zombie
%Cpu(s): 12.3 us,  4.1 sy,  0.0 ni, 81.9 id,  1.2 wa,  0.0 hi,  0.5 si,  0.0 st
MiB Mem :  16024.0 total,    528.0 free,   9216.0 used,   6280.0 buff/cache
MiB Swap:   8192.0 total,   3382.0 free,   4810.0 used.   6102.0 avail Mem

Load average — это число процессов готовых к выполнению или ожидающих непрерываемого I/O, усреднённое за 1/5/15 минут — это не процент. Load average 2.14 на 4-ядерной машине означает, что система загружена примерно вполовину от своего потолка; та же 2.14 на 1-ядерной машине означает больше чем двойную перегрузку.

Разбивка %Cpu(s) важнее единственного числа нагрузки: us (пользовательские процессы), sy (ядро/системные вызовы), wa (ожидание I/O — высокий wa при низких us/sy указывает на узкое место именно в хранилище, а не в CPU, хотя top и «инструмент по CPU»), si/hi (программные/аппаратные прерывания).

available память, а не free, — то число, которое реально важно. Linux агрессивно использует свободную RAM под дисковый кэш (buff/cache), потому что неиспользуемая RAM — потраченная впустую RAM — этот кэш мгновенно высвобождается, если приложению понадобится память. Система, показывающая «528MB free», но «6GB available», не испытывает нехватки памяти — она эффективно использует RAM.

vmstat для трендов во времени

$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0 3485536 528292 1293700 5136604    1    2   175  1239    2    1  9  6 76  5  5
 0  0 3485536 525352 1293704 5136692    0    0     0  7672 5709 9402  3  3 89  6  0

(vmstat 1 5 выводит раз в секунду, 5 раз.) Колонки, за которыми стоит следить:

  • r — процессы, реально выполняющиеся или готовые к выполнению прямо сейчас, конкурирующие за CPU. Если это число стабильно больше числа ядер — у вас реальная конкуренция за CPU.
  • b — процессы заблокированные, непрерываемо ожидающие (почти всегда дисковый I/O).
  • si/so — своп в/из. Любой устойчивый ненулевой so означает, что система активно выгружает память на диск — сильный сигнал реального давления на память, отличный от просто «мало свободной памяти» (которая, как выше, часто в порядке).

Поиск конкретного виновника

ps aux --sort=-%cpu | head -10     # топ потребителей CPU
ps aux --sort=-%mem | head -10     # топ потребителей памяти
pidstat 1 5                         # CPU по процессам во времени (нужен пакет sysstat)

Сужение именно до ожидания I/O

iostat -x 1 5

Колонка %util по устройству — ключевая: близко к 100% означает, что именно это устройство — узкое место, независимо от того, насколько «простаивающим» выглядит CPU в top.

Когда нужно глубже: perf

sudo apt install linux-tools-common linux-tools-$(uname -r)   # Debian/Ubuntu
sudo perf top                                                   # живое профилирование CPU на уровне символов

perf top показывает, какие именно функции (ядра или пользовательского пространства, если у бинарника есть символы) потребляют циклы CPU прямо сейчас — следующий уровень вглубь от «какой процесс» к «какая функция внутри этого процесса».

Различия Ubuntu/Debian и RHEL-подобных систем

top, vmstat, ps, free — часть procps, идентичны везде. pidstat/iostat приходят из пакета sysstat в обеих семьях, под теми же именами. Имя пакета для установки perf отличается (linux-tools-<версия-ядра> на Debian/Ubuntu против perf напрямую на RHEL-семействе), но использование идентично после установки.

Практическое задание

  1. Создайте искусственную нагрузку на CPU безопасным способом через yes > /dev/null & (направляет бесконечный поток символов y в никуда, забивая одно ядро) и понаблюдайте за ней в top — найдите её PID.
  2. Убедитесь через ps aux --sort=-%cpu | head -5, что тот же процесс наверху.
  3. Завершите его (kill <PID>) и убедитесь, что нагрузка возвращается к базовому уровню в течение нескольких секунд через vmstat 1 5.

Как проверить, что всё сделано правильно

  • Показатель us в %Cpu(s) top должен подскочить примерно до 100/<число ядер>% пока работает процесс yes (например, ~25% на 4-ядерной машине для одного такого процесса), и процесс должен быть виден наверху ps aux --sort=-%cpu.
  • После kill колонка r в vmstat должна вернуться к прежнему базовому уровню в течение пары секунд.

Типичные ошибки

  • Трактовка free памяти как важной метрики. Погоня за «почему так мало свободной памяти» на системе Linux, которая на самом деле здорова (высокий buff/cache, высокий available) — очень частый паттерн впустую потраченных усилий.
  • Диагностика «высокой нагрузки» как «высокой загрузки CPU» без проверки wa. Load average 8 при 90% wa и 5% us — это проблема I/O, не CPU — добавление ядер CPU тут не поможет.
  • Использование единственного снимка top вместо наблюдения за ним (или vmstat) во времени. Кратковременные всплески выглядят идентично устойчивым проблемам в одном снимке.

⚠ Опасные команды

  • kill -9 (SIGKILL) для процесса, держащего блокировку БД или находящегося посреди записи, может повредить данные — предпочитайте штатный kill (SIGTERM, по умолчанию) или собственный механизм остановки приложения сначала, оставляя -9 для процессов, реально не отвечающих на SIGTERM.
  • Запуск инструментов нагрузочного тестирования (вроде stress или цикла, забивающего CPU, как в задании выше) прямо на продакшн-системе, без предварительного подтверждения, что у вас есть безопасный способ его остановить, может вызвать реальный простой — всегда держите наготове команду kill в другом окне перед стартом.

Связанные статьи

Контрольные вопросы

  1. Почему система может показывать очень мало «свободной» памяти и при этом быть совершенно здоровой?
  2. На что указывает высокий процент wa в top, и почему добавление ядер CPU это не исправит?
  3. В чём разница между колонками r и b в выводе vmstat?
  4. Почему одного снимка top недостаточно для диагностики перемежающейся проблемы производительности?