There is one zombie process linux

Выполняю установку, настройку, сопровождение серверов. Для уточнения деталей используйте форму обратной связи

Что же это такое?
Это дочерний процесс в Unix-системе, завершивший своё выполнение, но ещё присутствующий в списке процессов операционной системы, чтобы дать родительскому процессу считать код завершения. Процесс при завершении освобождает все свои ресурсы (за исключением PID — идентификатора процесса) и становится «зомби» — пустой записью в таблице процессов, хранящей код завершения для родительского процесса.
Система уведомляет родительский процесс о завершении дочернего с помощью сигнала SIGCHLD. Предполагается, что после получения SIGCHLD он считает код возврата с помощью системного вызова wait(), после чего запись зомби будет удалена из списка процессов. Если родительский процесс игнорирует SIGCHLD (а он игнорируется по умолчанию), то зомби остаются до его завершения.

А теперь возникают вопросы: как же всё-таки их найти и убить? Найти их очень просто. Вот несколько вариантов:

1)
top | grep zombie
225 processes: 1 running, 222 sleeping, 2 zombie

2)
ps aux | grep -w Z
root 3994 0,0 0,0 0 0 ?? Z 13июн11 16:23,02
root 3995 0,0 0,0 0 0 ?? Z 13июн11 13:43,28

3)
ps -alx | awk ‘$10

Что касается «убийства», то их нельзя просто так убить. Самый правильный вариант — найти родительский процесс и перезапустить его. Некоторые могут посоветовать и перегрузиться, но это не выход.

Находим родительский процесс:

ps ajx | grep -w Z
root 3994 3992 3992 3992 0 Z ?? 16:23,02
root 3995 3992 3992 3992 0 Z ?? 13:43,28

3-я колонка как раз и показывает pid родительского процесса. Смотрим, что это за процесс:

ps auxww | grep 3992
root 3992 0,0 0,2 30664 9872 ?? Ss 13июн11 0:08,21 [exilog_agent] (perl5.12.3)

Собственно мы нашли виновника. Это exilog_agent. А дальше — либо просто прибиваем родительский процесс либо перезапускаем его:

#kill -9 3992
#top | grep zombie
#

Источник

Что означает «There is 1 zombie process» и что с ним делать?

Залогинился на удаленную машину. Вижу следующую строку в приветственном сообщении.

Насколько я понял, это означает, что какой-то процесс завершил работу, но не закрылся и не освободил ресурсы. Хотелось бы лучше понять проблему:

  • Как можно его обнаружить? Сейчас я угадал, но нужен стабильный метод.
  • Как можно узнать причины его появления? Есть какие-нибудь логи? Может, по имеющемуся процессу можно что-либо понять?

Если это важно, ubuntu 14.04, sudo есть.

Дополнение: меня не устраивает метод «просто подождать», т.к. есть сервис, который должен работать всегда — и подвис он или кто-то из его детей. Он подстрахован monit’ом, но тот не распознал зомбификацию и не перезагрузил.

1 ответ 1

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

Данная команда покажет все зомби процессы и их родителей (тестировалась под linux, под другими *nix возможны другие ключи у команды ps).

Убить зомби можно только перезапуском родительского процесса. kill -9 самого процесса-зомби и чеснок обычно не помогают. Если появление зомби разовое явление, то возможно проще на факт его появления забить.

Что бы понять почему именно появился зомби надо смотреть исходники породившего его процесса и возможно самого зомби. Часто это одна и та же программа. Любой процесс, выполняющий fork , т.е. запускающий дочерние процессы должен уметь забирать код их завершения, делается это вызовом wait и/или waitpid . Для начала надо просмотреть исходники на наличие функций группы wait, а так же наличие функции-обработчика сигнала SIGCHLD (обработчик устанавливается вызовом signal и функций для работы с сигналами потоков). Если родитель не использует функции группы wait, то возможно при его нормальной работе завершение дочерних процессов разработчик вообще не ожидал. Если это так — то причина образования зомби — незапланированное завершение процесса потомка в следствие какой либо ошибки. Дать рекомендаций как это искать и лечить невозможно. Можно только посоветовать добавить в родительский поток обработку CHLD, забор кода завершения с помощью wait и логирование факта завершения потомка. И дальше запуск потомка под отладчик и т.п. .

Вариант 2: родительский процесс использует wait , но зомби все равно появляются. Копать в сторону того, какая разновидность wait используется, если waitpid, которая проверяет завершение конкретных потомков, то смотреть откуда она берет проверяемые pid, возможно в процессе работы какие то pid потомков теряются и программа про них забывает. Может программа в какой то момент запрещает обработку сигналов и забывает восстановить обработку, после прохождения критического участка. Опять же — вариантов очень много, но сосредоточены они вокруг обработчика SIGCHLD и функций wait .

Вариант 3: родительский процесс умеет обрабатывать и готов правильно обработать завершение своих потомков. Но зацикливается в другом месте программы или засыпает на системном вызове, например чтения с сетевого диска, который стал недоступен и при этом прерывание по SIGCHLD запрещено. В этом случае надо разбираться с причинами его зависания. Кстати, отсутствие доступа к каким либо ресурсам, типа сетевых дисков (или при выходе из строя физического диска) — довольно частая причина массового появления зомби.

Читайте также:  Настройка plex для windows

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

Источник

Зомби процессы Linux

Каждая программа, которая выполняется в Linux, — это системный процесс, у которого есть свой идентификатор. Каждый процесс может запускать дочерние процессы с помощью функции fork. Такие процессы остаются под контролем родительского процесса и не могут быть завершены без его ведома. Если один из дочерних процессов всё же завершился, а его родительский процесс не смог получить об этом информацию, то такой дочерний процесс становится зомби.

Зомби процессы Linux не выполняются и убить их нельзя, даже с помощью sigkill, они продолжают висеть в памяти, пока не будет завершён их родительский процесс.

Посмотреть такие процессы можно с помощью утилиты ps, здесь они отмечаются как defunct:

ps aux | grep defunct

Если вы попытаетесь убить такой процесс с помощью сигнала KILL, то ничего не выйдет:

Чтобы его завершить, нужно найти «родителя» этого процесса. Для этого используйте команду:

ps -xal | grep defunct

Здесь идентификатор родительского процесса находится в четвёртой колонке (PPID). Теперь мы можем послать ему сигнал завершения, и такого процесса в системе больше не будет:

Для большего удобства вы можете использовать утилиты top или htop, но принцип их действия будет аналогичным, поэтому я не буду здесь его рассматривать. Теперь вы знаете, что делать, если в вашей системе появились зомби процессы Linux.

Источник

How to find zombie process?

How to find that zombie process?

8 Answers 8

To kill a zombie (process) you have to kill its parent process (just like real zombies!), but the question was how to find it.

Find the zombie (The question answered this part):

What you get is Zombies and anything else with a Z in it, so you will also get the grep:

Find the zombie’s parent:

In this case you do not want to kill that parent process and you should be quite happy with one zombie, but killing the immediate parent process 5145 should get rid of it.

Additional resources on askubuntu:

Even though this question is old I thought everyone deserved a more reliable answer:

This will emit two whitespace-delimited columns, the first of which is a PID and the second of which is its state.

I don’t think even GNU ps provides a way to filter by state directly, but you can reliably do this with awk

You now have a list of PIDs which are zombies. Since you know the state it’s no longer necessary to display it, so that can be filtered out.

Giving a newline-delimited list of zombie PIDs.

You can now operate on this list with a simple shell loop

ps is a powerful tool and you don’t need to do anything complicated to get process information out of it.

Less is more though:

That’s like, give me a forest (tree) of all users’ processes in a user oriented format with unlimited width on any tty and show it to me at half a screen above where it matches the case that the 8th column contains a Z, and why not highlight the whole line.

User oriented format seems to mean: USER, PID, %CPU, %MEM, VSZ, RSS, TTY, STAT, START, TIME, COMMAND so the Zombie status will show up in the 8th column.

You can throw in an N before the p if you want line numbers, and a J if you want an asterisk at the match. Sadly if you use G to not highlight the line that asterisk will not show, though J creates space for it.

You end up getting something that looks like:

You could follow this up with (and it’ll detect if your terminal likes -U Unicode or -A Ascii):

OR just, you know, use the up-arrow in less to follow that tree/forest through the hierarchy; which is what I was recommending with the «Less is more» approach.

Источник

Проблема PID 1 zombie reaping в Докере

Привет, Хабр!
Мы в Хекслете активно используем Докер как для запуска самого приложения и сопутствующих серверов, так и для запуска пользовательского кода в практических упражнениях по программированию. Без этих легковесных контейнеров нам было бы в разы сложнее справиться с этими задачами. Докер –замечательная технология, но иногда возникают неожиданные проблемы. Одна из таких проблем (и ее решение) описана в блоге Phusion (это создатели Phusion Passenger), сегодня мы публикуем ее перевод.

Примерно год назад, когда Докер был в версии 0.6, мы первыми представили Baseimage-docker. Это минимальный образ Ubuntu, модифицированный специально для Докера. Люди могут пуллить этот базовый образ из Docker Registry и использовать его как основу для своих образов.

Мы были ранними пользователям Докера, используя его для CI и для создания рабочего окружения задолго до выхода версии 1.0. Базовый образ мы сделали чтобы решить проблемы, специфичные для принципов работы Докера. Например, Докер не запускает процессы под специальным процессом init, который бы правильно обрабатывал дочерние процессы, поэтому возможна такая ситуация, когда зомби-процессы вызывают кучу проблем. Докер также не делает ничего с syslog, поэтому важные сообщения могут быть утеряны. И так далее.

Читайте также:  Что делать если тормозит нетбук windows

Однако, мы выяснили, что многие люди не понимают проблем, с которыми мы столкнулись. Да, это довольно низкоуровневые системные механизмы Unix, которые понятны далеко не всем. Поэтому в этом посте мы опишем самую главную проблему, которую мы решаем – PID 1 zombie reaping problem.

Оказалось:

  1. Проблемы, которые мы решаем, актуальны для многих людей.
  2. Многие люди не знают об их существовании, поэтому в какой-то момент обязательно начинаются неожиданные неполадки (закон Мерфи).
  3. Будет очень неэффективно если каждый будет решать проблемы самостоятельно.

Поэтому мы вынесли решение в универсальный базовый образ, который может использовать каждый: Baseimage-docker. Этот образ добавляет кучу полезных инструментов, необходимых (как мы считаем) разработчику Докер-образов. Мы используем Baseimage-docker как основу для все своих образов.

Сообществу нравится что мы делаем: наш образ третий по популярности в Docker Registry после официальных образов Ubuntu и CentOS.

The PID 1 problem: сбор зомби

Все процессы в Unix представлены в виде дерева. Каждый процесс порождает дочерние процессы, и каждый процесс имеет родителя кроме самого верхнего (или корневого).

Корневой процесс это init. Он запускается ядром при загрузке системы. init отвечает за старт остальных частей системы, например, демона SSH, демона Докера, запуск Apache/Nginx, запуск графического интерфейса и так далее. Каждый из них в свою очередь запускает свои дочерние процессы.

Ничего необычного. Но что происходит когда процесс завершается? Допустим, процесс bash (PID 5) был завершен. Он превращается в так называемый “defunct process”, также известный как “процесс зомби”.

Почему это происходит? Unix сделан таким образом, что родительский процесс ждет завершения дочернего чтобы получить код завершения (exit status). Зомби процесс существует до тех пор, пока родительский процесс не закончит это действие, используя семейство системных вызовов waitpid(). Вот цитата из man:

A child that terminates, but has not been waited for becomes a “zombie”. The kernel maintains a minimal set of information about the zombie process (PID, termination status, resource usage information) in order to allow the parent to later perform a wait to obtain information about the child.

Обычно люди считают зомби процессы какими-то сбежавшими процессами, вызывающими беспорядок. Но формально, с точки зрения операционной системы Unix, зомби процессы имеют четкое определение. Это процессы, которые завершились, но их родительские процессы еще ждут их завершения.

В большинстве случаев это не проблема. Системный вызов waitpid() для обработки зомби называют “reaping” (сбор, обработка). Многие приложения обрабатывают свои дочерние процессы корректно. В примере с sshd выше если bash завершается, то ОС пошлет сигнал SIGCHLD процессу sshd чтобы разбудить его. Sshd заметит это и обработает (“reaps”) дочерний процесс.

Но есть особый случай. Представьте себе, что родительский процесс завершился, намеренно или из-за действия пользователя. Что происходит с его дочерними процессами? У них больше нет родителя, поэтому они становятся “сиротами” (это технический термин).

Тут в игру вступает процесс init. У процесса init – PID 1 – есть специальная задача: “усыновлять” осиротевшие процессы (это снова настоящий технический термин). Это означает, что init становится родителем таких процессов, не смотря на то, что они в реальности не были порождены init’ом.

Рассмотрим пример с Nginx, который демонизируется по-умолчанию. Он работает следующим образом: сначала Nginx создает дочерний процесс. Потом основной процесс Nginx завершается. Теперь дочерний процесс Nginx усыновлен init’ом.

Ядро ОС ожидает от init специального поведения: ядро считает, что init должен обрабатывать (собирать, “reap”) усыновленные процессы тоже.

Это очень важная функция в Unix. Она настолько фундаментальна, что многие программы рассчитаны на ее корректную работу. Большинство демонов рассчитано на то, что демонизированные процессы будут усыновлены и обработаны (то есть корректно завершены после превращения в зомби) init’ом.

Я использую демоны в качестве примера, но этот механизм распространяется не только на них. Каждый раз когда процесс, имеющий детей, завершается, он ожидает, что init подчистит все за ним. Это описано детально в двух очень хороших книгах: Operating System Concepts и Advanced Programming in the UNIX Environment.

Почему процессы зомби вредны

Почему зомби-процессы вредны, не смотря на то, что они всего лишь завершенные процессы? Ведь наверняка память, выделенная процессу уже освобождена, и зомби это всего лишь строка в ps?

Да, память этого процесса уже освобождена. Но тот факт, что процесс еще виден в ps означает, что он использует ресурсы ядра. Вот цитата из man по waitpid:

As long as a zombie is not removed from the system via a wait, it will consume a slot in the kernel process table, and if this table fills, it will not be possible to create further processes.

До тех пор пока zombie не удален из системы с помощью wait, он будет использовать слот в таблице процессов ядра, и если эта таблица заполнится, создание новых процессов будет невозможно

Причем тут Докер

Причем же тут Докер? Многие люди запускают только один процесс в своем контейнере. Но скорее всего этот процесс не ведет себя как правильный init. То есть вместо корректной обработки усыновленных процессов, он считает, что другой init процесс должен делать это. И считает так совершенно справедливо.

Давайте рассмотрим конкретный пример. Допустим, ваш контейнер содержит веб-сервер, в котором крутится CGI-скрипт, написанный на bash. Скрипт вызывает grep. Потом веб-сервер решает, что скрипт обрабатывается слишком долго и убивает его. Но grep остается запущенным. Когда он заканчивает свою работу, он превращается в зомби и усыновляется процессом PID 1 (веб-сервером). Веб-сервер не знает ничего про grep, поэтому не обрабатывает его завершение и зомби-grep остается в системе.

Читайте также:  Как очистить диск для переустановки windows

Проблема применима и к другим ситуациям. Многие создают контейнеры для сторонних приложений, например, PostgreSQL, и запускают эти приложения как единственный процесс внутри контейнера. Когда вы запускаете чужой код, уверены ли вы что он не порождает дочерние процессы, которые потом превратятся в зомби? Если вы запускаете свой код и точно знаете, что он и используемые им библиотеки делают, то все хорошо. Но в общем случае необходимо запускать правильный init для решения проблем.

Но разве запуск полного системного init не превращает контейнер в тяжелую штуку вроде виртуальной машины?

Система init не обязательно тяжелая. Возможно, вы думаете про Upstart, Systemd, SysV и так далее. Возможно, вам кажется, что внутри контейнера нужно запустить целую систему. Это не так. “Полная система init” не обязательна и не нужна.

Необходимая нам система это простая маленькая программа, задача которой это запуск вашего приложения и сбор усыновленных процессов. Использование такой простой init системы полностью соответствует философии Докера.

Простая init система

Возможно, есть готовые решения? Почти. Старый добрый bash. Bash обрабатывает усыновленные процессы. Bash может запустить что угодно. Так что вместо такой строчки в Dockerfile…

(директива -e запрещает bash’у распознавать скрипт как простую команду и exec()’ать его напрямую).

В итоге получится такая иерархия процессов:

Но, к сожалению, у этого подхода есть проблема. Он не обрабатывает сигналы! Допустим, вы используете kill чтобы послать сигнал SIGTERM процессу bash. Bash завершается, но не посылает SIGTERM своим дочерним процессам!

Когда bash завершается, ядро завершает весь контейнер со всеми процессами внутри. Эти процессы завершаются с помощью SIGKILL. Поэтому нет способа завершить эти процессы чисто. Допустим, ваше приложение пишет что-то в файл. Файл может быть поврежден если приложение завершилось таким образом во время записи. Нечистое завершение процессов это плохо. Это почти как выдернуть шнур питания у сервера.

Но почему нас должно волновать, что процесс init завершается сигналом SIGTERM? Потому что docker stop посылает SIGTERM процессу init. “docker stop” должен остановить контейнер правильно, чтобы его можно было потом запустить с помощью “docker start”.

Эксперты по bash наверняка захотят написать нормальный обработчик EXIT, который посылает сигналы своим детям, вроде такого:

К сожалению, это не решает проблемы. Посылать сигналы дочерним процессам недостаточно. init также должен ожидать завершения дочерних процессов перед тем, как завершаться самому. Если init завершится раньше, то все дочерние процессы будут убиты (не чисто) ядром.

Очевидно, требуется чуть более сложное решение, но полная система init с Upstart, Systemd и SysV это слишком жирно для легковесного докер-контейнера. К счастью, Baseimage-docker содержит решение. Мы написали свою, легкую систему init специально для использования внутри докер-контейнера. Не придумав ничего лучше, мы назвали ее my_init. Это программа на Питоне в 350 строк.

Ключевые функции my_init:

  • Обработает (reap) дочерние процессов
  • Запускает подпроцессы
  • Ожидает завершения всех подпроцессов перед собственным завершением, с максимальным таймаутом
  • Записывает активность в “docker logs”

Решит ли Докер эту проблему сам?

В идеале, проблема с PID 1 должна решаться нативно самим Докером. Было бы здорово, но пока, в январе 2015 года, мы не слышали ничего подобного от команды Докера. Это не критика – Докер очень амбициозен, и я уверен, что у их команды есть проблемы поважнее. Проблема PID 1 легко решается на пользовательском уровне. Так что пока Докер не решит эту проблему официально, мы рекомендуем людям решать ее самим, используя систему вроде той, что описана выше.

Проблема ли это вообще?

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

Не забывайте про закон Мерфи.

Кроме того, что зомби забивают таблицу ресурсов ядра, они также могут мешать корректной работе программ, которые проверяют наличие процессов. Например, Phusion Passenger управляет процессами. Он перезапускает процессы при их падении. Он парсит вывод ps и отправляет сигнал 0 процессу. Зомби виден в ps и реагирует на сигнал 0, так что Phusion Passenger думает, что процесс все еще жив.

Все, что нужно чтобы обезопасить себя от проблемы с зомби, это потратить 5 минут на подключение Baseimage-docker или на импорт 350 строк my_init. Дополнительные затраты на диск и память минимальны: в память добавляется лишь пара мегабайт.

Заключение

Проблема PID 1 – реальна. Один из способов ее решения – использовать Baseimage-docker. Единственный ли это путь? Конечно, нет. Цели Baseimage-docker это:

  1. Рассказать людям о нескольких важных моментах при работы с Докер-контейнерами.
  2. Предоставить готовое решение чтобы люди не изобретали велосипед.

При этом возможны несколько решений, главное чтобы они справлялись с описанной задачей. Можете написать свой вариант на C, Go, Ruby или чем-то еще.

Возможно, вы не хотите использовать базовый образ Ubuntu. Может, вы используете CentOS. Но Baseimage-docker все равно может быть вам полезен. Например, проект ourpassenger_rpm_automation использует контейнеры CentOS. Мы просто извлекли my_init и вставили его туда.

Источник

Оцените статью