Learning Platform
Глоссарий Troubleshooting
Урок 04.04 · 22 мин
Начальный
pspgrepkill/procSignalsTools

Тулзы для процессов — ps, pgrep, kill, /proc

В предыдущих уроках мы разобрали, как процессы устроены и как живут. Теперь — инструментарий: как смотреть, искать, управлять процессами в практической работе. Эти инструменты вы будете использовать каждый день: дебажить «почему сервис не отвечает», искать «кто съел всю память», отправлять сигналы перезагрузить конфиг.

В этом уроке — глубокое погружение в ps, pgrep, kill, pstree, и работу с /proc/[pid]/. После урока вы должны уверенно ориентироваться в любой системе и за минуту понимать, что в ней происходит.


ps: швейцарский нож для процессов

ps — самый базовый инструмент. У него тяжёлая история: он поддерживает три разных синтаксиса (BSD, SysV, GNU long options). Это часто путает. Запомните несколько проверенных вариаций.

Часто используемые варианты

# Простой список процессов в системе (SysV style):
ps -ef
# UID PID PPID C STIME TTY TIME CMD

# То же, но BSD style:
ps aux
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

# Дерево процессов:
ps -ejH       # тоже самое в формате SysV
ps axjf       # BSD

# Конкретный пользователь:
ps -u username
ps -U username   # реальный UID, а не effective

# Конкретные процессы по имени:
ps -C nginx    # точное имя
ps -fp 1234    # по PID, полные поля

# Mои процессы:
ps -ef -u $(id -u)

Кастомный вывод колонок

Самый мощный режим — ps -eo, где вы сами выбираете столбцы:

ps -eo pid,user,uid,nice,pri,rss,vsz,wchan,stat,start_time,cmd --sort=-rss | head -10

Что значат колонки:

Основные колонки ps
pidProcess ID. Уникальное число процесса в системе
ppidParent PID. Кто создал процесс. Чтобы найти иерархию
userEffective user (после setuid). uid -- real, ruid -- real, euid -- effective
statState letter (R/S/D/T/Z) с flags (+, s, l, etc). Главный индикатор состояния процесса
rssResident Set Size в KB. Сколько физической памяти реально занято процессом сейчас. То, что важно для memory usage
vszVirtual Size в KB. Сколько виртуальной памяти выделено. Обычно сильно больше rss из-за overcommit и mmap'ов
%memПроцент от общей RAM. Удобно для сортировки по памяти
%cpuПроцент CPU за всё время жизни процесса. НЕ instantaneous -- усреднено за всё время
priТекущий приоритет процесса (внутренний). Чем меньше, тем приоритет выше (странная инверсия в Unix)
niceNice value: -20..19, по умолчанию 0. -20 = высокий приоритет, 19 = низкий. Можно менять renice
wchanWait Channel: на каком kernel syscall процесс ждёт (для S/D state). - значит running. Очень помогает диагностике
cmdКомандная строка. Можно увидеть, какие аргументы переданы

Полезные сценарии ps

# Топ-10 процессов по памяти:
ps -eo pid,user,rss,vsz,cmd --sort=-rss | head -10

# Топ-10 по CPU (накопительному):
ps -eo pid,user,%cpu,%mem,cmd --sort=-%cpu | head -10

# Все процессы, которые в состоянии D (uninterruptible):
ps -eo stat,pid,wchan,cmd | awk '$1 ~ /^D/'

# Все zombies:
ps -eo stat,pid,ppid,cmd | awk '$1 ~ /^Z/'

# Процессы с большим nice (низкий приоритет):
ps -eo pid,nice,cmd | awk '$2 > 0'

# Сколько потоков у процесса:
ps -o nlwp= -p 1234

# Все процессы с одного PPID (одного родителя):
ps -ef | awk '$3 == "1234"'

top и htop: интерактивный мониторинг

ps — статический снимок. Для реального времени — top (всегда есть) или htop (улучшенный, надо ставить).

# Базовый top:
top

# С обновлением каждые 0.5 секунды:
top -d 0.5

# Только конкретного пользователя:
top -u username

# Сортировка по памяти:
top -o RES    # или нажмите M внутри top

# Один снимок без интерактивности (для скриптов):
top -bn1 | head

Internals top:

  • Первая строка — uptime, load average.
  • Вторая — task counts.
  • Третья — %CPU breakdown.
  • Четвёртая-пятая — mem и swap.
  • Остальное — процессы.

В top интерактивно нажмите:

  • 1 — показать CPU на каждое ядро отдельно.
  • H — показывать потоки, а не процессы.
  • c — полная командная строка.
  • M — сортировка по памяти.
  • P — сортировка по CPU.
  • k — послать сигнал процессу.
  • r — renice (изменить приоритет).

htop гораздо удобнее: цвета, поиск (F3), tree view (F5), kill (F9). Если есть возможность установить — ставьте.

sudo apt install htop      # Debian/Ubuntu
sudo dnf install htop      # Fedora

pgrep и pkill: поиск процессов по имени/атрибутам

pgrep ищет процессы и возвращает PID, pkill — то же, но сразу убивает.

# Найти процессы по имени:
pgrep nginx
# 1234
# 5678

# Точное имя (по умолчанию substring):
pgrep -x nginx

# Имя процесса + полная командная строка:
pgrep -fl nginx

# Пользователя:
pgrep -u username

# Внуки определённого процесса:
pgrep -P 1234   # дети PID 1234

# Самый новый/старый процесс этого имени:
pgrep -n nginx   # newest
pgrep -o nginx   # oldest

pkill идентичен по аргументам, но сразу шлёт сигнал (SIGTERM по умолчанию):

# Послать SIGTERM всем nginx:
pkill nginx

# SIGKILL (форсированно):
pkill -9 nginx

# По пользователю:
pkill -u username -9
# (опасно! Убивает все процессы пользователя)

Будьте аккуратны: pkill -9 -u username без проверки можно увидеть себя в ssh-сессии, как она обрывается :)


kill: отправка сигналов

kill — классическая команда. Несмотря на название, она не только убивает — она шлёт сигналы.

# Послать SIGTERM (по умолчанию):
kill 1234

# SIGKILL (нельзя поймать, форсированно):
kill -9 1234

# SIGHUP (часто используется для reload config):
kill -1 1234
# или
kill -HUP 1234

# Список всех сигналов:
kill -l
# 1) SIGHUP  2) SIGINT  3) SIGQUIT  4) SIGILL  ...

Часто используемые сигналы

Сигналы и kill: как правильно убивать процессы
Часто используемые сигналы Unix
SIGTERM 15Termination request: 'пожалуйста, закройся'. Программа может перехватить и сделать cleanup. Стандартный сигнал для graceful shutdown
SIGKILL 9Kill немедленно. Нельзя перехватить, нельзя проигнорировать. Программа не успеет cleanup. Используйте только если SIGTERM не сработал
SIGINT 2Interrupt: Ctrl-C в терминале. Просит программу выйти. Можно поймать, часто игнорируется в скриптах
SIGHUP 1Hangup. Исторически: терминал был отключён. Сейчас: даемоны используют для перечитки config (nginx -s reload, apache reload)
SIGUSR1 10User-defined 1. Программа сама определяет, что делать. Например, nginx использует для reopen log files
SIGUSR2 12User-defined 2. Аналогично USR1, ещё один customizable
SIGSTOP 19Stop. Приостанавливает процесс. Нельзя перехватить. Возобновить через SIGCONT
SIGCONT 18Continue. Возобновить остановленный процесс
SIGQUIT 3Quit с core dump. Ctrl-\\. Программа может перехватить, по умолчанию -- crash с core dump
SIGSEGV 11Segmentation fault. Доступ к невалидной памяти. Обычно баг, программа крашится с core dump
SIGPIPE 13Broken pipe. Запись в pipe/socket с другой закрытой стороной. По умолчанию убивает -- настоящая частая причина 'неожиданного' завершения
SIGCHLD 17Child stopped/exited. Родитель получает, когда ребёнок завершился. Нужен для wait()

Граceful shutdown: SIGTERM перед SIGKILL

Хороший паттерн при выключении сервиса:

# Послать SIGTERM, ждать 10 секунд:
kill 1234
sleep 10

# Проверить, жив ли:
if kill -0 1234 2>/dev/null; then
    # Ещё жив -- послать SIGKILL
    kill -9 1234
fi

kill -0 не шлёт сигнал, просто проверяет, существует ли процесс и есть ли права. Используется для проверки.

systemd делает это автоматически: при systemctl stop посылает SIGTERM, ждёт TimeoutStopSec (по умолчанию 90s), потом SIGKILL.

Сигналы в Python

import signal
import sys
import time

def handler(signum, frame):
    print(f"Got signal {signum}, exiting...")
    sys.exit(0)

# Перехватить SIGTERM и SIGHUP
signal.signal(signal.SIGTERM, handler)
signal.signal(signal.SIGHUP, handler)

print(f"PID: {os.getpid()}, waiting for signal...")
while True:
    time.sleep(1)

Запустите, в другом терминале kill <PID> — увидите graceful exit. kill -9 <PID> — мгновенная смерть без handler (SIGKILL нельзя перехватить).


pstree: иерархия процессов

pstree показывает дерево процессов. Удобно понять, кто кого запустил.

# Всё дерево:
pstree

# С PID:
pstree -p

# Конкретного пользователя:
pstree -u username

# Поддерево конкретного PID:
pstree -p 1234

# Linkage между потоками:
pstree -T   # без потоков
pstree -t   # с потоками

Пример вывода:

systemd(1)
├── NetworkManager(820)
├── sshd(945)
│   └── sshd(2345)
│       └── bash(2348)
│           ├── htop(8901)
│           └── pstree(9001)
├── nginx(1234)
│   ├── nginx(1235)
│   ├── nginx(1236)
│   └── nginx(1237)
└── ...

Видно: systemd — PID 1. sshd запустил вашу bash-сессию (2348). bash запустил htop и pstree. nginx запустил воркеров.

Эта картина помогает понять «структуру» системы: где сервисы, какие у них воркеры, что запускает что.


Глубокая диагностика через /proc/[pid]

Когда стандартных тулзов не хватает — лезьте прямо в /proc/[pid]/. Это все данные о процессе из ядра.

Содержимое /proc/[pid]/ — что где

ls /proc/$$/   # вашего shell

Главные файлы:

  • status — человекочитаемое состояние (Name, State, PID, PPID, Uid, VmRSS, …).
  • stat — то же одной строкой (для ps, top).
  • maps — виртуальная память.
  • smaps — то же + детально по каждой VMA (резидент, swap, dirty).
  • cmdline — argv процесса.
  • environ — окружение.
  • cwd -> symlink на текущую директорию.
  • exe -> symlink на бинарь.
  • fd/ — открытые файлы как symlinks.
  • wchan — на каком syscall ждёт.
  • stack — kernel stack trace (требует root).
  • io — I/O статистика: сколько прочёл/записал.
  • limits — ulimits процесса.
  • task/ — подкаталог на каждый поток процесса.

Полезные одностроки

PID=1234   # подставьте свой

# Полная информация:
cat /proc/$PID/status

# Что процесс читает/пишет:
cat /proc/$PID/io
# rchar: 12345  -- сколько байт прочитал через read syscalls
# wchar: 5678   -- сколько записал через write
# syscr: 100    -- сколько read syscalls
# syscw: 50     -- сколько write syscalls
# read_bytes: 8192   -- реально с диска
# write_bytes: 4096  -- реально на диск

# Открытые файлы:
ls -la /proc/$PID/fd/

# Какие файлы и сокеты держит процесс:
ls -la /proc/$PID/fd/ | head
# lrwx------ 1 user user 64 May 18 14:00 0 -> /dev/null
# lrwx------ 1 user user 64 May 18 14:00 1 -> /var/log/app.log
# lrwx------ 1 user user 64 May 18 14:00 2 -> /var/log/app.log
# lrwx------ 1 user user 64 May 18 14:00 3 -> socket:[12345]
# lrwx------ 1 user user 64 May 18 14:00 4 -> /etc/myapp.conf

# Карта памяти:
cat /proc/$PID/maps | head

# Сколько памяти каждая VMA реально занимает (с резидентностью):
cat /proc/$PID/smaps | head -50

# Где процесс висит:
cat /proc/$PID/wchan
# Если запущен -- '0', если sleeps -- имя kernel-функции (например, ep_poll, futex_wait)

# Стек вызовов в ядре (требует root):
sudo cat /proc/$PID/stack | head -10

lsof — удобная обёртка над /proc

Сетевая диагностика: ping, dig, ss, nc, traceroute

lsof (List Open Files) — удобная утилита для просмотра открытых файлов:

# Все открытые файлы конкретного процесса:
lsof -p 1234

# Все процессы, использующие файл:
lsof /var/log/syslog

# Все TCP сокеты в LISTEN состоянии:
lsof -iTCP -sTCP:LISTEN

# Кто слушает на порту 80:
lsof -i :80

# Что использует /tmp:
lsof +D /tmp

lsof показывает не только файлы, но и сокеты, pipes, devices. Очень мощный.


ulimit: лимиты процесса

Свой systemd-сервис: пишем .service unit

У каждого процесса есть лимиты:

  • Максимум открытых fd (ulimit -n)
  • Максимум памяти (ulimit -m, обычно unlimited)
  • Максимум CPU time (ulimit -t)
  • Максимум size of core dumps (ulimit -c)
  • Максимум size of stack (ulimit -s)
  • Максимум количество процессов на user (ulimit -u)
# Посмотреть лимиты текущего shell:
ulimit -a

# Открытые fd:
ulimit -n
# Обычно 1024

# Поднять для текущего shell (если разрешено):
ulimit -n 65536

# Лимиты конкретного процесса:
cat /proc/<PID>/limits

В production это критично для серверов. Nginx или PostgreSQL хотят открыть много fd (тысячи сокетов и файлов). Лимит 1024 — мало. Поднимают через systemd unit (LimitNOFILE=65536) или /etc/security/limits.conf.


Реальные сценарии

Сценарий 1: «Что-то ест память, не знаю что»

# Топ-10 по RSS:
ps -eo pid,user,rss,vsz,cmd --sort=-rss | head -11

# Если самый большой -- это Python скрипт:
PID=12345
cat /proc/$PID/status | grep -E '^Vm|^Threads'
# VmPeak: 4194304 kB  -- максимум, что когда-либо было allocated
# VmSize: 3000000 kB  -- сколько сейчас virtual
# VmRSS:  1500000 kB  -- сколько физически (это реальная нагрузка на RAM)
# Threads: 16        -- столько threads

# Карта памяти:
cat /proc/$PID/smaps | grep -E '^(Size|Rss|Pss|Shared|Private)' | head -50
# Видно, какие отдельные mapping'и сколько занимают

Сценарий 2: «Процесс висит, что делает»

# State:
ps -o stat,wchan -p $PID
# D ext4_sync_file  -- висит в fsync ext4
# или
# S futex_wait_queue -- ждёт synchronization
# или
# S inet_csk_accept -- ждёт TCP connection

# Активные syscalls:
sudo strace -p $PID 2>&1 | head -10
# Покажет, на каких syscall'ах висит

# Что в стеке (требует root):
sudo cat /proc/$PID/stack | head

Сценарий 3: «Не могу удалить файл, говорит busy»

# Файл /var/log/old.log не удаляется -- кто его держит:
lsof /var/log/old.log
# Видно процесс. Можно его убить, или попросить переоткрыть лог (kill -HUP).

Сценарий 4: «Слишком много open files, EMFILE»

# Лимит:
ulimit -n

# Реальное количество fd у процесса:
ls /proc/$PID/fd/ | wc -l

# Что за fd, может быть утечка (тысячи sockets):
ls -la /proc/$PID/fd/ | awk '{print $11}' | sort | uniq -c | sort -rn | head

Попробуй сам

# 1. Найти топ-5 процессов по памяти:
ps -eo pid,user,rss,vsz,cmd --sort=-rss | head -6

# 2. Посмотреть всё про себя (shell):
cat /proc/$$/status | head -20
ls -la /proc/$$/fd/
cat /proc/$$/limits

# 3. Trace процесс:
sleep 30 &
PID=$!
sudo strace -p $PID 2>&1 | head -5
# Покажет на каком syscall ждёт (nanosleep)
kill $PID

# 4. Sigtest -- послать сигнал, посмотреть как программа реагирует:
sleep 100 &
PID=$!
kill -STOP $PID
ps -o stat,pid -p $PID   # T+
kill -CONT $PID
ps -o stat,pid -p $PID   # S
kill $PID

# 5. Посмотреть, кто слушает на портах:
sudo lsof -iTCP -sTCP:LISTEN -P -n | head

# 6. Изменить приоритет (nice) тяжелого процесса:
nice -n 19 sha256sum /etc/* > /dev/null &
PID=$!
ps -o pid,ni,pri,cmd -p $PID
# Видно nice=19, низкий приоритет
kill $PID

# 7. Дерево процессов:
pstree -p $$ | head

# 8. Найти zombie:
ps -eo stat,pid,cmd | awk '$1 ~ /^Z/' | head
# Может быть пусто, если нет zombies

Проверка знанийKnowledge check
Junior выясняет, что сервис postgres ест 8GB памяти, но free показывает только 2GB used. Куда делись остальные 6GB? Postgres лжёт?
ОтветAnswer
Не лжёт. Это классическая путаница, основанная на нескольких разных понятиях памяти. Разберём по полочкам. (1) ps/top показывают разные виды памяти: - VSZ (VmSize) -- виртуальная память. Сколько процесс 'аллоцировал' в своём виртуальном пространстве. Может быть гигантский (десятки GB), потому что mmap-ит много файлов, shared libraries и memory не значит, что физически занято. - RSS (VmRSS) -- резидентная память. Сколько физических страниц в RAM прямо сейчас. То, что реально в физическом RAM. - PSS -- proportional set size. RSS, поделённый между процессами, которые делят страницы. Самый честный показатель, когда есть shared memory. (2) Что значит 8GB у Postgres. Скорее всего это VmRSS или VSZ. - Если VSZ -- это иллюзия. Postgres mmap-ит файлы данных, но не все страницы реально в RAM. - Если RSS -- это РЕАЛЬНАЯ физическая память. Тогда 'остальные 6GB' где-то. (3) Postgres использует shared memory. Большая её часть -- shared_buffers (page cache Postgres). Этот сегмент shm shared между всеми worker процессами. Если у Postgres 100 worker'ов и shared_buffers 4GB, каждый worker покажет RSS включая эти 4GB. Если просто складывать RSS всех worker'ов -- получите 'занято' в 100 раз больше, чем реально. - Правильно смотреть PSS, не RSS. cat /proc/[pid]/smaps_rollup | grep Pss -- честная цифра. (4) free -h показывает 'used' = total - free - buffers - cached - SReclaimable. Это очень специфический счёт. Buffer/cache -- эта память используется ядром для page cache (читай: страницы файлов, прочитанные с диска). Когда программа запросит память -- ядро освободит cache. Поэтому 'used' в free -- это 'занято процессами, без кэша'. 'available' -- сколько программам можно ещё взять. (5) Где смотреть правильно. free -h, потом ВНИМАТЕЛЬНО: - total -- сколько всего RAM - used -- сколько занято процессами и kernel structures (без кэша) - free -- абсолютно ничем не занято - buff/cache -- page cache + dentry cache (освобождается под нужды программ) - available -- реально доступно для программ (used + cache - reclaimable) Итог: ваш Postgres скорее всего показывает RSS включая shared memory, которая считается у каждого worker'а одинаково. free показывает 'used' без page cache. Реальное потребление 'physical RAM' у Postgres -- меньше, чем сумма RSS worker'ов, но больше, чем free показывает 'used'. Используйте PSS для точного учёта, или просто наблюдайте available.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. Чем отличаются колонки RSS и VSZ в выводе ps?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4