Короткий ответ

Load average — очередь, не «проценты CPU». Сначала разберите, какой счётчик красный: %usr, %sys, %iowait, %irq, %steal. iowait лечат диск/NFS, не kill -9 PHP. steal — гипервизор, не гостевой nginx. Только после типа нагрузки ищите PID через pidstat/top. Reboot сбрасывает улики и не чинит цикл, который поднимется снова.

Хост host.example (10.0.20.10), пользователь admin. Пакет sysstat даёт mpstat/pidstat — поставьте его заранее, не в инцидент.

Симптомы и как отличить

  • uptime показывает load 40 на 4 vCPU;
  • htop красный, Steal колонка ненулевая;
  • приложение «висит», CPU в top почти нулевой — это не эта статья, это I/O lock или зависание;
  • после cron по ночам всплеск — смотрите cron и бэкапы.
МетрикаСмыслНе делайте
%usrкод процессаreboot
%sysядро, syscalls, сетьотключать firewall «навсегда»
%iowaitCPU ждёт дискkill случайных PID
%stealгипервизор забрал CPUапгрейд nginx в госте
%softsoftirq, сетьбез ss/nstat

Возможные причины

  1. Запросный шторм приложения (usr): бесконечный цикл, regex, json.
  2. gzip/gpg/mysqldump без nice/ionice.
  3. kswapd и сжатие памяти — уже RAM/swap.
  4. Журналы на медленном диске, journald — iowait.
  5. Steal на перепроданном VPS.
  6. unattended-upgrades + needrestart + apt в рабочее время.
  7. Редко: IRQ шторм NIC, soft lockup — граница с hang.

Диагностика

1. Ядра и load

nproc
lscpu | grep -E 'Model name|CPU\(s\)|Hypervisor'
uptime
cat /proc/loadavg

Сравните 1/5/15 минут: пик одной минуты vs плато 15 минут.

2. Тип CPU

mpstat -P ALL 1 5
vmstat 1 10

Читайте us sy id wa st. На Ubuntu без sysstat: top и клавиша 1 по ядрам.

3. Кто ест usr/sys

pidstat -u 1 5
ps aux --sort=-pcpu | head -n 15
top -b -n 1 -o %CPU | head -n 20

Для потоков: pidstat -t -p <pid> 1 3. Java без имён потоков — jstack уже в зоне приложения.

4. iowait

iostat -xz 1 5
pidstat -d 1 5
df -h

Высокий await и %util на одном устройстве: тот диск. Если это / забитый логами — диск.

5. Steal и соседи

В госте:

mpstat 1 5 | awk '/Average/ {print}'
dmesg -T | grep -i steal | tail

На гипервизоре (если ваш) смотрите CPU overcommit. Внутри Ubuntu steal не вылечить systemctl restart.

6. Короткий perf (если пакет linux-tools установлен)

sudo perf top -g --delay 50

Не оставляйте perf record на часы на проде без лимита размера.

systemctl status $(ps -o pid= -C nginx | head -n 1)
systemd-cgtop -n 1

Решение

Сценарий A. Понятный пользовательский процесс

Ограничьте, не убивайте вслепую: systemctl set-property app.service CPUQuota=200% (временно), либо остановите job (бэкап) штатно. Для одноразового gzipkill -TERM после подтверждения, что это тот PID.

Сценарий B. iowait из‑за логов/диска

Ротация, vacuum journal, перенос I/O. Reboot не ускоряет диск.

Сценарий C. Steal

Миграция VM, резерв CPU, меньше соседей. В госте можно только снизить нагрузку.

Сценарий D. kswapd / высокая sys при нехватке RAM

Идите в статью про RAM и OOM. Добавление «ещё PHP-FPM children» ухудшит.

Сценарий E. Нужен профиль на 30 секунд

sudo timeout 30 perf record -g -a -o /tmp/perf.data
sudo perf report --stdio | head

Снимите файл в заявку, не интерпретируйте один swapper как виновника.

Как не перепутать steal, guest и «надо больше vCPU»

В KVM колонка st в vmstat/mpstat — время, которое гипервизор не дал vCPU. Внутри гостя nginx innocent. Лечение: меньше CPU overcommit, CPU pinning, миграция на другой хост. Добавление workers PHP увеличит очередь и steal.

На 24.04 systemd-cgtop показывает CPU% по unit — удобно, когда top полон потоков java. Для user-сессии admin тяжёлый rsync живёт в user-1000.slice и выглядит как «система тормозит», хотя это один человек.

Краткий профиль без perf, если linux-tools нет в политике:

cat /proc/$(pidof -s nginx)/sched
grep -H . /proc/$(pidof -s nginx)/status | grep -E 'PPid|Threads|voluntary'
ls /proc/$(pidof -s nginx)/task | wc -l

Для iowait на md/RAID смотрите cat /proc/mdstat и iostat -x md0. Rebuild массива даёт высокий wait при скромном usr — reboot только прервёт rebuild.

Если load высокий ночью ровно в 6:25 — это /etc/crontab run-parts, не DDoS. Снимите pidstat в это окно и сравните с cron.

nproc в контейнере может показывать ядра хоста при cgroup CPUQuota. Смотрите cat /sys/fs/cgroup/cpu.max (cgroup v2 на Ubuntu 22.04/24.04 по умолчанию). Load 16 при quota 100% одного CPU — нормальная очередь, не «сломался scheduler».

На госте с cpu cfs quota колонка %idle в mpstat может быть высокой при огромном load: процессы runnable ждут квоты, это не iowait. Смотрите /sys/fs/cgroup/cpu.stat поле nr_throttled. Если throttled растёт — увеличивать quota или снижать concurrency, не reboot.

Как проверить, что проблема устранена

uptime
mpstat 1 5
pidstat -u 1 3
ssh -o ConnectTimeout=5 admin@10.0.20.10 true

Load 15-минутный падает медленно — смотрите 1-минутный и %idle. Функциональный запрос к приложению должен уложиться в обычный SLA.

Если не помогло

  • CPU низкий, всё равно «висит»: сервер зависает, locks, D-state.
  • После kill нагрузка на другом PID — оркестратор поднимает реплики, чините причину трафика.
  • soft lockup в dmesg — hang/NMI, не «просто CPU».
  • Нагрузка только в IRQ: cat /proc/interrupts, очередь NIC, не apt.

Профилактика

  • Базовый sysstat (sar), экспорт node-exporter: cpu/iowait/steal отдельно.
  • CPUAccounting=yes на тяжёлых unit.
  • Окна бэкапа не в пик пользовательской нагрузки.
  • Лимиты cgroup в юнитах, не надежда на «диск большой».

FAQ

Load 100 при 4 ядрах — это 2500% CPU?

Нет. Load — длина очереди.runnable+uninterruptible. При iowait очередь растёт без 100% usr.

Нужен ли nice -n 19 всем cron?

Для тяжёлых job — да, плюс ionice -c3. Не nice'айте sshd.

Почему htop показывает 400%?

Сумма по потокам. Делите на nproc.

Можно ли отключить SMT против нагрузки?

Не как лечение инцидента. Это решение про латентность/безопасность на железе, не про runaway PHP.

perf запрещён политикой?

Тогда pidstat, /proc/<pid>/stack, bpftrace если разрешён. Reboot всё ещё не диагностика.