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

4. Процессы, CPU, память


PID/PPID, load average, OOM Killer, память (RSS/VSZ/page cache/swap), nice/renice и основы cgroups — для диагностики тормозов и падений в production.


PID и PPID

PID (Process ID) — уникальный идентификатор процесса в системе. PPID (Parent Process ID) — PID родительского процесса. Дерево процессов строится по этим связям; init/systemd (PID 1) — корень. Команды: ps -ef, ps -o pid,ppid,cmd, pstree. При «зомби» или зависших дочерних процессах смотрят родителя (PPID) и перезапускают сервис или корректно завершают потомков.


Context switching

Переключение контекста (context switch) — когда ядро забирает CPU у одного процесса и отдаёт другому: сохраняется контекст (регистры, состояние) первого, подгружается контекст второго. Частые переключения создают накладные расходы (кэш, TLB). Высокий показатель context switch при нормальном CPU может означать много потоков/процессов, конкурирующих за CPU, или активный I/O (процессы часто блокируются и просыпаются). Смотреть: vmstat 1, pidstat -w, в /proc: контекстные переключения по системе и по процессам.


Load average

Load average — три числа (за 1, 5 и 15 минут), показывающие среднее число процессов в состоянии готовы к выполнению (runnable) или ожидания I/O (uninterruptible sleep, D). Не «процент CPU», а «сколько процессов в среднем ждали CPU или диск». Интерпретация:

  • На одноядерной системе load 1.0 — в среднем один процесс ждал; load 4.0 — в среднем четыре.
  • На 4 ядрах load 4.0 может быть нормой (все ядра заняты), а load 16 — сильная перегрузка (много ожидающих).

Высокий load при низком CPU часто говорит о I/O wait: процессы ждут диск или сеть (состояние D), CPU простаивает. Смотреть: top (wa — iowait), iostat, vmstat (блоки в io). Высокий load при высоком CPU — много вычислений, процессы конкурируют за процессор; смотреть, какие процессы: top, pidstat, perf.


OOM Killer

Когда ядру не хватает памяти (включая учёт буферов и возможности вытеснения в swap), оно вызывает OOM Killer и завершает один или несколько процессов, чтобы освободить память. В логах (dmesg, journalctl) появляются сообщения вида «Out of memory: Killed process …». Выбор жертвы основан на oom_score и oom_score_adj; можно понижать приоритет для важных процессов (меньше шанс быть убитым). После OOM в логах видно PID и имя процесса; дальше — разбирать, почему память закончилась (утечка, неверные лимиты, нехватка ресурса на машине).


Память: RSS, VSZ, page cache, swap

RSS и VSZ

  • RSS (Resident Set Size) — объём физической памяти (RAM), занятой процессом (его страницами). То, что реально давит на RAM.
  • VSZ (Virtual Size) — размер виртуального адресного пространства процесса (включая отображённые файлы, разделяемые библиотеки, ещё не загруженные страницы). Обычно больше RSS.

В top, ps смотрят RSS для оценки «кто сколько ест» памяти. Сортировка по памяти: в top — M, в ps — ps -eo pid,rss,vsz,cmd --sort=-rss.

Page cache и swap

  • Page cache — кэш страниц файлов в RAM. Свободная память ядро использует под кэш; при нехватке памяти кэш вытесняется. В free видно «cached»; «available» — оценка памяти, доступной для приложений (с учётом возможности освободить кэш).
  • Swap — вынос страниц на диск (swap-раздел или файл). При активном swap диски активно пишут/читают, система может «тормозить». Мониторить: free, vmstat, swapon -s.

Nice, renice и cgroups (база)

Nice и renice

Nice — значение приоритета планировщика для процесса (-20 … 19). Чем выше nice (например, 19), тем ниже приоритет — процесс получает меньше CPU при конкуренции. Запуск с пониженным приоритетом: nice -n 19 heavy_task. Изменить у уже работающего: renice -n 19 -p <PID>. Обычные пользователи могут только повышать nice (ухудшать приоритет); понижать (улучшать) может root.

cgroups (control groups)

cgroups — механизм ядра для ограничения, учёта и приоритизации ресурсов (CPU, память, I/O) группой процессов. systemd, Docker, Kubernetes используют cgroups для лимитов. Версия интерфейса — cgroups v2 (единая иерархия в /sys/fs/cgroup/). Ограничение CPU и памяти для сервиса задаётся в unit-файле (CPUQuota, MemoryMax) или через директории cgroup вручную. Понимание нужно для настройки лимитов контейнеров и сервисов и для диагностики (кто упирается в лимит).


Практика

Найти процесс, который съедает память

# Сортировка по RSS (top — нажать M для сортировки по памяти)
ps -eo pid,rss,vsz,cmd --sort=-rss | head -20

# Или через top
top -o %MEM

# Детали по процессу (smaps — разбивка памяти)
cat /proc/<PID>/status | grep -i mem

По PID смотреть логи и конфигурацию приложения; при утечке — перезапуск или обновление.

Понять разницу между high load и high CPU

  • High load, high CPU — много процессов активно считают. Смотреть top, pidstat 1 — какие процессы занимают CPU; оптимизация кода, масштабирование, лимиты.
  • High load, low CPU — процессы в основном ждут I/O (диск, сеть). Смотреть iostat -x 1, vmstat 1 (wa, блоки io), возможно диск или сеть — узкое место. Увеличить ресурс I/O или уменьшить нагрузку на диск/сеть.

Ограничить CPU и память через cgroups

В systemd для сервиса в unit-файле (или в override):

[Service]
CPUQuota=50%        # не более 50% одного ядра (или 0.5 ядра при 100%)
MemoryMax=512M      # жёсткий лимит памяти
MemoryHigh=400M     # мягкий лимит (давление, но не kill)

Перезагрузка конфига и сервиса:

sudo systemctl daemon-reload
sudo systemctl restart myservice

Проверка: systemctl show myservice -p MemoryCurrent,MemoryMax; для процесса — в какую cgroup попал: cat /proc/<PID>/cgroup.

!!! tip "Практика"

При инциденте «всё тормозит» или «процесс убит»: 1) load average и %CPU/%wa в top; 2) free и swap; 3) топ процессов по RSS и по CPU; 4) dmesg/journal на OOM; 5) при необходимости лимиты cgroups и их достижение.

Паттерны и антипаттерны

Паттерн Описание
Смотреть load и CPU вместе Высокий load при низком CPU — I/O; при высоком CPU — вычисления.
Лимиты памяти для сервисов MemoryMax в systemd или аналог в оркестраторе, чтобы один процесс не съел всю машину.
После OOM — логи и тренд памяти Понять, утечка или пиковая нагрузка; добавить лимиты или ресурс.
Антипаттерн Почему плохо Что делать
Игнорировать swap при тормозах Активный swap даёт задержки на I/O. Увеличить RAM или снизить потребление; swap как страховка, не как основной объём.
Ставить только CPU limit без памяти OOM может убить важный процесс. Задавать и MemoryMax (или аналог) для предсказуемого поведения.

Дополнительные материалы