1. Иерархия процессов и жизненный цикл задач в ядре Ubuntu
Иерархия процессов и жизненный цикл задач в ядре Ubuntu
Вы отправляете команду kill -9 зависшему процессу, но он продолжает нагло висеть в списке задач. Вы отправляете сигнал снова и снова, но ничего не меняется. Знакомая ситуация? Эта аномалия происходит потому, что в Linux процессы — это не просто изолированные программы в вакууме. Это живая экосистема со строгой генеалогией, где каждый процесс имеет родителя, проходит через конкретные фазы жизни и даже после смерти должен быть правильно «похоронен». Чтобы эффективно диагностировать сервер, нужно перестать смотреть на процессы как на плоский список и увидеть их истинную структуру.
Анатомия и генеалогия: PID и PPID
Для ядра Ubuntu любая запущенная программа, скрипт или системная служба — это задача (task). Чтобы ядро могло управлять тысячами задач, оно присваивает каждой из них уникальный идентификатор — PID (Process ID).
Но ядро никогда не создает процессы из ниоткуда. В Linux действует строгий принцип: каждый новый процесс создается уже существующим процессом. Тот, кто создает, называется родителем, а созданный — потомком. Поэтому у каждого процесса, помимо собственного PID, всегда есть PPID (Parent Process ID) — идентификатор его создателя.
> Процесс в Linux — это экземпляр выполняемой программы, которому ядро выделило ресурсы (память, процессорное время, файловые дескрипторы) и назначило уникальные идентификаторы PID и PPID.
Механика создания выглядит так:
fork(): родительский процесс клонирует сам себя. Создается точная копия с новым PID, но с данными родителя.execve() (или функции семейства exec()): процесс-потомок заменяет свою скопированную память кодом новой программы, которую мы на самом деле хотели запустить.Дерево процессов: кто стоит у истоков
Если каждый процесс создается другим процессом, возникает логичный вопрос: кто создал самый первый процесс?
При загрузке Ubuntu, как только ядро инициализирует оборудование, оно запускает самую первую программу в пользовательском пространстве — систему инициализации systemd.
Процесс systemd всегда имеет PID 1. Это корень всего дерева процессов в современной Ubuntu. Абсолютно все остальные процессы в системе являются его прямыми или косвенными потомками.
Рассмотрим типичную цепочку при подключении к серверу:
systemd (PID 1) запускает службу SSH-сервера — sshd.sshd создает дочерний процесс для вашей сессии.sshd запускает вашу командную оболочку — например, bash.top, и bash порождает процесс top.!Древовидная иерархия процессов в Linux с системным менеджером systemd в качестве корневого процесса.
Понимание этой иерархии критически важно для диагностики. Если вы завершите родительский процесс (например, вашу сессию bash), операционная система автоматически отправит сигнал завершения всем его потомкам.
Жизненный цикл: больше, чем просто «работает»
Процесс не находится в процессоре 100% времени. Ядро постоянно переключает контекст, давая поработать разным задачам. В любой момент времени процесс находится в одном из строго определенных состояний.
В утилитах мониторинга (таких как top или ps) это состояние отображается одной латинской буквой в колонке S (State).
* R (Running / Runnable) — процесс либо прямо сейчас выполняется на ядре процессора, либо стоит в очереди и готов к выполнению.
* S (Interruptible Sleep) — процесс спит, ожидая какого-то события (например, ввода с клавиатуры или поступления сетевого пакета). Его можно разбудить сигналом. Большинство процессов в системе находятся именно в этом состоянии, не потребляя ресурсы CPU.
* D (Uninterruptible Sleep) — процесс ждет аппаратного ответа (чаще всего от диска) или захвата блокировки. Это самое важное состояние для диагноста. Традиционно процесс в состоянии D нельзя прервать или убить даже командой kill -9 (хотя в современных ядрах появился подтип TASK_KILLABLE, позволяющий завершить процесс фатальным сигналом). Если на сервере много процессов в статусе D, это верный признак проблем с дисковой подсистемой (I/O bottleneck).
* T (Stopped) — процесс приостановлен (например, комбинацией Ctrl+Z в терминале). Он находится в оперативной памяти, но ядро не дает ему процессорное время, пока не поступит сигнал продолжения (SIGCONT).
Патологии: Сироты и Зомби
Строгая иерархия «родитель-потомок» иногда дает сбой, порождая два специфических состояния, с которыми администраторы сталкиваются при отладке.
Процессы-сироты (Orphans)
Что произойдет, если родительский процесс завершится раньше, чем его потомок? Потомок останется без родителя — станет сиротой. Ядро Linux не допускает нарушения древовидной структуры. Если процесс осиротел, он немедленно «усыновляется» ближайшим предком, который объявил себя «subreaper» (с помощью настройкиPR_SET_CHILD_SUBREAPER, что часто используют менеджеры контейнеров). Если такого предка нет, сирота достается корневому процессу — systemd (PID 1). Это нормальная практика: именно так работают классические демоны (фоновые службы), которые специально отвязываются от терминала, чтобы продолжить работу после вашего отключения.Процессы-зомби (Zombies, статус Z)
Это та самая ситуация из начала статьи. Зомби — это процесс, который уже завершил свое выполнение (умер), освободил оперативную память и закрыл файлы.Почему же он висит в списке процессов?
По правилам Linux, родитель должен «прочитать» статус завершения своего потомка (узнать, завершился ли он с ошибкой или успешно), вызвав функцию wait(). Пока родитель этого не сделает, ядро хранит запись о мертвом процессе в таблице процессов.
Зомби — это не программа, это просто строчка в системной таблице. Он не потребляет ни CPU, ни RAM. Однако он занимает один PID. Если криво написанная программа будет бесконечно плодить потомков и не читать их статусы, таблица процессов переполнится, и система не сможет запустить ни одной новой команды.
Убить зомби напрямую невозможно — он уже мертв. Команда kill -9 на него не подействует. Чтобы очистить таблицу от зомби, нужно заставить его родителя прочитать статус завершения. Если родитель завис и не делает этого, единственный выход — убить самого родителя. Тогда зомби станет сиротой, его усыновит systemd, который автоматически и мгновенно очищает статусы всех своих мертвых «детей».
Понимание того, как процессы рождаются, меняют состояния и умирают, дает нам фундамент. Теперь, когда мы видим процесс в состоянии D или Z, мы понимаем природу происходящего. В следующей главе мы спустимся на уровень ниже и посмотрим, где именно ядро хранит всю эту информацию в реальном времени, изучив виртуальную файловую систему /proc.