Главная мысль урока проста: load average врет про причину. Он показывает усредненную за 1, 5 и 15 минут длину очереди задач, но не говорит, кто эту очередь создал, и сильно сглажен по времени. Хуже того, в Linux в load average попадают не только процессы, ждущие CPU, но и процессы в состоянии непрерываемого сна (D-state) - те, что висят на диске или NFS. Поэтому load 20 на 4 ядрах может быть и чистым CPU, и зависшим диском. А вот vmstat и mpstat показывают честную раскадровку - на что реально уходит каждая секунда работы CPU и сколько процессов толпится в очереди на исполнение прямо сейчас.
Как устроена нагрузка на CPU и при чем тут run queue
Представь кассу в магазине. Ядро процессора - это касса, а процессы (точнее потоки) - покупатели. В каждый момент касса обслуживает ровно одного. Остальные, кто готов платить прямо сейчас, стоят в очереди. Вот эта очередь готовых-к-работе задач и называется run queue. Если у тебя 4 ядра (4 кассы), то 4 покупателя обслуживаются одновременно, и это нормально. А если в очереди стабильно висит 12 готовых задач на 4 ядра - касс не хватает, система в насыщении (saturation). Каждая задача ждет своей доли CPU, растет задержка планировщика, и все тормозит, хотя сами ядра при этом загружены на 100% и работают изо всех сил.
Ключевое слово - готовых. Задача, которая спит в ожидании ответа от диска или сети, в run queue НЕ стоит. Она в блокировке. Поэтому большой run queue - это именно нехватка процессора, а не диска. Это и есть простое правило, которое мы будем проверять: сравниваем число в колонке r с количеством ядер. Узнать число ядер легко:
Код: Выделить всё
nproc
# или подробнее, с разбивкой на сокеты/ядра/потоки
lscpu | grep -E "^CPU\(s\)|Core|Socket|Thread"
vmstat linux: читаем по колонкам и ловим насыщение
Запускать vmstat без аргументов почти бесполезно: первая строка - это средние с момента загрузки сервера, мусор для диагностики. Нам нужна динамика в реальном времени, поэтому добавляем интервал в секундах:
Код: Выделить всё
vmstat 1Код: Выделить всё
vmstat -w -t 1Код: Выделить всё
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
8 0 0 201160 88540 1340220 0 0 0 16 5210 9300 78 12 9 1 0
9 1 0 200980 88540 1340220 0 0 0 0 5102 9011 81 11 8 0 0- r - сколько задач готовы выполняться: либо уже на CPU, либо ждут в run queue. Здесь 8 и 9. Если у нас 4 логических ядра, а r стабильно держится 8-9 - это насыщение, процессора не хватает вдвое.
- b - сколько процессов в непрерываемом сне (uninterruptible sleep, состояние D). Чаще всего это ожидание ввода-вывода: диск, NFS, иногда блокировки в ядре. Если b постоянно больше нуля - смотри в сторону диска или сети, а не CPU. Тонкость: b - это не "ждут CPU", а именно "застряли в ядре", их легко спутать с r.
- si - сколько килобайт в секунду подкачивается ИЗ свопа в память (swap in).
- so - сколько уходит В своп (swap out).
Группа system:
- in - прерываний в секунду (interrupts). Аппаратные сигналы от сетевой карты, диска, таймера.
- cs - переключений контекста в секунду (context switches). Сколько раз в секунду планировщик переключал ядро CPU с одной задачи на другую.
Группа cpu - проценты, в сумме всегда дают 100:
- us (user) - время на код приложений в пользовательском пространстве. Высокий us - работает твой код: PHP, Python, JVM, расчеты. Это "хорошая" загрузка, если она оправдана.
- sy (system) - время в ядре: системные вызовы, работа с сетью и файлами. Аномально высокий sy - подозрение на шквал syscall'ов, сетевой флуд или неэффективный код.
- id (idle) - процессор простаивает. Если тут стабильный 0 - CPU выжат досуха.
- wa (iowait) - CPU простаивает, потому что ждет диск. Высокий wa = узкое место в диске, а не в процессоре. Важно понимать, что iowait - это разновидность idle: ядро не занято, оно просто ждет io, и эти такты можно было бы отдать другой задаче, если бы она была.
- st (steal) - украденное время. Актуально на виртуалках и в облаке: гипервизор отдал твои такты соседу. Ненулевой st на VPS означает, что сосед по железу объедает тебя.
mpstat: ловим дисбаланс по ядрам
vmstat показывает CPU целиком, одной усредненной строкой. И тут прячется коварная ловушка. Допустим, у тебя 8 ядер. Одно ядро забито на 100%, остальные семь спят. Усреднение даст примерно 12% - и vmstat покажет, будто процессор почти свободен. А приложение при этом стоит колом, потому что уперлось в одно ядро. Чтобы это увидеть, нужна разбивка по каждому ядру. Ее дает mpstat (пакет sysstat, ставится как sysstat в apt/dnf):
Код: Выделить всё
mpstat -P ALL 1Код: Выделить всё
CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
all 13.20 0.00 1.50 0.10 0.00 0.30 0.00 0.00 0.00 84.90
0 99.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
1 1.00 0.00 0.50 0.00 0.00 0.00 0.00 0.00 0.00 98.50
2 0.80 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 99.00Поля mpstat детальнее, чем cpu-группа vmstat, и это его сила:
- %usr - пользовательский код, %nice - то же, но процессы с пониженным приоритетом (nice), %sys - ядро, %idle - простой, %iowait - ожидание диска, %steal - украдено гипервизором.
- %irq и %soft - обслуживание аппаратных и программных прерываний (softirq). Высокий %soft именно на одном-двух ядрах - классический симптом, когда все прерывания сетевой карты привязаны к этим ядрам. На сетевом сервере смотри сюда первым делом.
- %guest и %gnice - время на исполнение виртуальных CPU (актуально на хосте гипервизора, на обычной VM это нули).
Что нового в 2026: PSI и eBPF поверх классики
vmstat и mpstat живы и прекрасно работают, но в современном ядре (cgroup v2 по умолчанию во всех актуальных дистрибутивах - Ubuntu, Debian, RHEL-семейство, Astra Linux, RED OS) появились средства точнее. Самое полезное на 2026 - PSI, Pressure Stall Information. Это встроенный в ядро счетчик, который прямо отвечает на вопрос "насколько система задыхается из-за нехватки CPU", без гадания по r:
Код: Выделить всё
cat /proc/pressure/cpuКогда надо понять не "сколько" задач в очереди, а "как долго" каждая ждет, на сцену выходит eBPF. Инструменты runqlat и runqlen (из пакетов bpftrace или bcc-tools, в свежих дистрибутивах ставятся штатно) дают то, чего нет у vmstat:
- runqlat - гистограмма задержки планировщика (run queue latency): сколько микросекунд задача ждала своей очереди на CPU. Если хвост гистограммы уезжает в миллисекунды - планировщик не успевает, CPU перегружен, и это видно в цифрах задержки, а не косвенно.
- runqlen - гистограмма длины очереди по каждому ядру, семплируется на 99 Гц. Прямо показывает дисбаланс: на одном ядре очередь, на другом пусто.
sar: смотрим в прошлое, когда инцидент уже прошел
vmstat и mpstat хороши, когда проблема прямо сейчас перед глазами. А если ночью сервер задыхался, а к утру отпустило? Тут спасает sar из того же пакета sysstat - он пишет историю в фоне. Если служба сбора включена, данные пишутся автоматически каждые несколько минут. Посмотреть нагрузку CPU за сегодня:
Код: Выделить всё
sar -u
# конкретный диапазон времени
sar -u -s 02:00:00 -e 04:00:00
# за конкретную дату (файлы лежат в /var/log/sa/ или /var/log/sysstat/)
sar -u -f /var/log/sa/sa14
# разбивка по ядрам из истории
sar -P ALLКод: Выделить всё
sudo systemctl enable --now sysstatТипичные грабли и заблуждения
- Верить load average про причину. Load 20 на 4 ядрах может быть и из-за CPU, и из-за зависшего диска: процессы в состоянии D попадают в load, но это не процессор. Всегда проверяй vmstat: высокий r - это CPU, высокий b и wa - это io.
- Читать первую строку vmstat. Она усреднена с момента загрузки и не отражает текущий момент. Смотри со второй строки.
- Доверять усреднению. Главная причина, по которой одной vmstat недостаточно. Всегда добавляй mpstat -P ALL, чтобы не пропустить ядро в полке за красивым средним.
- Забывать про SMT. Порог по r считай по логическим ядрам (nproc), но помни, что SMT-потоки не равны полноценным ядрам, и реальное насыщение наступает чуть раньше.
- Игнорировать st на виртуалке. Если в облаке тормозит, а us/sy низкие - смотри %steal. Это не твоя вина, это сосед или переподписка хостера.
- Путать b и r. r - готовы работать (нужен CPU). b - застряли в непрерываемом сне на io (нужен диск/сеть). Это разные болезни и разное лечение.
- Не смотреть PSI в контейнерах. На 2026 cpu.pressure конкретного cgroup точнее покажет, какой именно сервис душит CPU, чем общесистемный vmstat.
- Узнай число логических ядер: nproc. Запиши.
- Открой два терминала. В первом запусти vmstat 1, во втором mpstat -P ALL 1.
- Создай нагрузку на одно ядро: Посмотри в mpstat - одно ядро уйдет в %usr под 100, остальные останутся в idle. Вот он, дисбаланс, своими глазами. Параллельно глянь
Код: Выделить всё
yes > /dev/null &- some avg10 поползет вверх.Код: Выделить всё
cat /proc/pressure/cpu - Запусти нагрузку на все ядра (по числу из nproc, например 4): Теперь смотри vmstat: колонка r поднимется к числу ядер и выше, id упадет в 0. Это и есть наполнение run queue.
Код: Выделить всё
for i in $(seq 4); do yes > /dev/null & done - Если установлены bpftrace или bcc-tools, в третьем терминале запусти и посмотри, как растет задержка планировщика под нагрузкой.
Код: Выделить всё
sudo runqlat 5 1 - Обязательно прибей фоновые процессы, чтобы не жгли CPU зря:
Код: Выделить всё
pkill yes
- У тебя 8 логических ядер, а колонка r в vmstat стабильно держит 24. О чем это говорит и куда копать?
- vmstat показывает %idle около 90, но приложение жестко тормозит. Какой утилитой и каким флагом ты проверишь, не упирается ли все в одно ядро?
- Колонки si и so в vmstat показывают устойчивые ненулевые значения. Имеет ли смысл дальше профилировать CPU и почему?
- Чем принципиально отличается колонка r от колонки b в группе procs и что показывает /proc/pressure/cpu по сравнению с ними?
vmstat 1 - твой первый взгляд на систему: run queue (r) против числа логических ядер ловит насыщение CPU, si/so ловят своп, wa и b ловят диск, st ловит проблемы виртуализации. mpstat -P ALL 1 вскрывает дисбаланс по ядрам, который усреднение прячет: одно ядро в полке при общем низком потреблении - это либо однопоточное узкое место, либо привязка прерываний (%soft). sar -u дает историю, чтобы разобрать инцидент задним числом. А на 2026 поверх этой классики стоит /proc/pressure/cpu (PSI) для прямой оценки давления на CPU и runqlat/runqlen на eBPF для точной задержки планировщика. Освоишь эти команды - и нагрузка на сервер перестанет быть загадкой.