Ответ
Зомби-процессы (состояние Z в ps) — это завершенные процессы, чей статус выхода не был прочитан родительским процессом. Я решаю эту проблему системно, а не просто "убивая" процессы.
Диагностика и решение:
-
Поиск зомби-процессов:
# Все зомби в системе ps aux | awk '$8 ~ /^[Zz]/ {print $0}' # Более детально с PPID (Parent Process ID) ps -eo pid,ppid,stat,comm | grep -w Z # Пример вывода: # PID PPID STAT COMMAND # 12345 67890 Z [python] <defunct> -
Правильное "убийство" зомби:
# 1. Отправить SIGCHLD родителю (запросить чтение статуса) kill -s SIGCHLD 67890 # PPID из примера выше # 2. Если не помогло - аккуратный restart родителя systemctl restart my-service # для systemd сервисов # 3. Крайний случай - kill родителя kill -TERM 67890 # SIGTERM сначала sleep 5 kill -KILL 67890 # SIGKILL если не сработало -
Профилактика в приложениях:
# Пример для Python приложения import signal import os # Обработчик SIGCHLD def handle_sigchld(signum, frame): try: while True: # waitpid с WNOHANG не блокирует pid, status = os.waitpid(-1, os.WNOHANG) if pid == 0: break print(f"Child {pid} exited with status {status}") except ChildProcessError: pass signal.signal(signal.SIGCHLD, handle_sigchld) -
Для контейнеров (Docker/Kubernetes):
# Dockerfile - использование init процесса FROM alpine:latest # tini или dumb-init как PID 1 RUN apk add --no-cache tini ENTRYPOINT ["/sbin/tini", "--", "python", "app.py"] # Или в docker run # docker run --init my-image
Важные моменты:
- Зомби не потребляют CPU/память, только запись в таблице процессов
- init (PID 1) автоматически убирает зомби, если их родитель умер
- В контейнерах проблема частая, т.к. приложение часто становится PID 1 без proper signal handling
- Мониторинг:
# Nagios/Icinga проверка ZOMBIES=$(ps aux | awk '$8 ~ /^[Zz]/' | wc -l) if [ $ZOMBIES -gt 10 ]; then echo "CRITICAL: $ZOMBIES zombie processes" exit 2 fi