← Linux: процессы вглубь
12 мин · средне · Урок 6 из 7

Наблюдение: ps, lsof, strace

Наблюдение за процессами: ps, lsof, strace, /proc.

Три угла зрения на один процесс

Когда сервис ведёт себя странно, полезно посмотреть на него с трёх сторон: что за процессы вообще запущены, какие файлы и соединения они держат, какие системные вызовы делают прямо сейчас. Под каждый вопрос есть свой инструмент.

ps даёт снимок. lsof показывает открытые файлы и сокеты. strace подслушивает системные вызовы. Ниже по одному примеру на каждый, а в конце тот же результат напрямую из ядра через /proc.

ps: снимок процессов

ps aux печатает разом все процессы в системе. Вывод — таблица с фиксированными колонками:

$ ps aux
USER   PID %CPU %MEM    VSZ   RSS STAT START  TIME COMMAND
root     1  0.0  0.1 168240 11500 Ss   09:00  0:02 /sbin/init
www     812  1.3  2.4 720160 98400 Sl   09:01  0:21 nginx: worker

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

КолонкаЗначение
USERвладелец процесса
PIDномер процесса
%CPUдоля процессора
%MEMдоля физической памяти
RSSреально занятая память в КБ (Resident Set Size)
STATсостояние (R, S, D, Z, T)
COMMANDчто запущено

Одна ловушка: обычный ps aux показывает процессы, а не потоки внутри них. Многопоточный сервис выглядит одной строкой, хотя внутри крутится десяток threads. Потоки вытаскивает флаг -L:

ps -L -p 812      # каждый поток процесса 812 отдельной строкой (колонка LWP)

lsof: какие файлы открыл процесс

lsof (list open files) отвечает на вопрос «что этот процесс держит открытым». В Linux открытым файлом считается и обычный файл, и сокет, и устройство, и pipe.

По PID:

$ lsof -p 812
COMMAND PID USER   FD   TYPE DEVICE  SIZE/OFF   NODE NAME
nginx   812  www  cwd    DIR    8,1      4096      2 /
nginx   812  www    6u  IPv4  18432       0t0    TCP *:http (LISTEN)
nginx   812  www    9u   REG    8,1     14210 262145 /var/log/nginx/access.log

Обратный вопрос — «кто занял порт 80»:

lsof -i :80       # процессы, слушающие или использующие порт 80

Это первый ход, когда сервис не стартует с ошибкой «address already in use»: lsof -i :<порт> сразу назовёт PID того, кто порт уже держит.

Тот же вопрос бывает шире: кто держит не отдельный файл, а целую точку монтирования. Это классика ошибки umount: target is busy, когда раздел не отмонтировать, потому что внутри него кто-то работает. lsof +f -- /mnt/data перечислит процессы с открытыми файлами на этой точке, fuser -m /mnt/data выдаст короткий список PID.

$ lsof +f -- /mnt/data
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
python  5120  app    3w   REG   8,17    20480  132 /mnt/data/import.csv

$ fuser -m /mnt/data
/mnt/data:            5120

Дальше по ситуации: остановить сервис, дождаться конца записи или снять процесс сигналом. Точка отмонтируется, когда её отпустит последний держатель.

strace: какие системные вызовы делает процесс

Системный вызов (syscall) — это обращение процесса к ядру: открыть файл, прочитать сокет, выделить память. strace перехватывает эти вызовы и печатает их в реальном времени.

Подключиться к уже работающему процессу по PID:

$ strace -p 812
read(6, "GET / HTTP/1.1\r\n"..., 8192) = 79
openat(AT_FDCWD, "/var/www/index.html", O_RDONLY) = 11
write(9, "192.168.1.10 - - [11/Jul...]", 64) = 64

Чаще всего strace нужен в двух ситуациях. Процесс завис: видно, на каком вызове он остановился (например, read из сокета, который никто не пишет). Или процесс не находит файл, тогда в выводе всплывает строка вида:

openat(AT_FDCWD, "/etc/app/config.yml", O_RDONLY) = -1 ENOENT (No such file or directory)

ENOENT прямо говорит: искомого пути нет. Дальше остаётся понять, почему процесс ждёт его именно там.

Здесь вторая ловушка. strace не бесплатен: он перехватывает каждый syscall, и нагруженный процесс под ним заметно тормозит, иногда в разы. На боевом сервисе с трафиком его вешают ненадолго и осознанно, а не оставляют висеть.

/proc: те же данные напрямую от ядра

Каталог /proc/<PID>/ — это интерфейс ядра к состоянию процесса, отдаётся как обычные файлы. ps и lsof во многом читают именно его.

cat /proc/812/status      # PID, PPID, состояние, память, потоки (Threads:)
cat /proc/812/cmdline     # командная строка, аргументы разделены \0
ls  -l /proc/812/fd       # открытые дескрипторы: симлинки на файлы и сокеты

ls -l /proc/812/fd показывает то же, что lsof -p 812, только без обёртки:

lrwx------ 1 www www 64 Jul 11 09:01 6 -> socket:[18432]
l-wx------ 1 www www 64 Jul 11 09:01 9 -> /var/log/nginx/access.log

Сигналы: что стоит помнить рядом

Наблюдая за процессом, часто им же и управляют сигналами. Пара фактов, о которые легко споткнуться.

Перехватить, заблокировать или проигнорировать нельзя ровно два сигнала: SIGKILL и SIGSTOP. Остальные процесс волен обработать по-своему.

У сигнала есть действие по умолчанию, если обработчик не задан. Их пять: Term (завершить), Ign (проигнорировать), Core (завершить с дампом), Stop (остановить), Cont (продолжить). Например, SIGCHLD по умолчанию относится к Ign: процесс не обязан реагировать на завершение потомка.

Про зомби из прошлого урока: запись зомби в таблице процессов держит только номер PID, память процесса уже освобождена. Когда родитель умирает раньше потомка, осиротевшего усыновляет init (PID 1) и вызывает для него wait(), так что вечных зомби под нормальным init не бывает. С ядра 3.4 роль такого сборщика можно передать заранее назначенному процессу через subreaper, а не только PID 1.

Что важно запомнить

ps aux — снимок процессов и их ресурсов; потоки только с флагом -L.

lsof -p <PID> — открытые файлы процесса, lsof -i :<порт> — кто занял порт, lsof +f -- /mnt и fuser -m /mnt — кто держит точку монтирования.

strace -p <PID> — системные вызовы в реальном времени; ENOENT = файл не найден. На нагруженном проде вешать осторожно, он тормозит процесс.

/proc/<PID>/ (status, fd, cmdline) — те же данные напрямую от ядра.

SIGKILL и SIGSTOP не перехватить; действий по умолчанию пять (Term/Ign/Core/Stop/Cont); осиротевший процесс усыновляет PID 1.

Дальше — короткий квиз по треку процессов.

Дрилл · вопросы как на собесе

Проверь себя без подсказок

Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.

01

Где хранится информация о процессах в Linux?

LIN-027
02

Как понять, какими процессами используется раздел?

LIN-093

Прошли материал до конца? Отметьте урок пройденным.