[Перевод] Обработка зомби-процессов в PostgreSQL: что делать?

Процесс-зомби (zombie process) — дочерний процесс в Unix-системе, завершивший своё выполнение, но ещё присутствующий в списке процессов операционной системы, чтобы дать родительскому процессу считать код завершения. Обычно, когда процесс завершает выполнение и работу, операционная система собирает статус завершения дочернего процесса с помощью системных вызовов wait () или waitpid (), выполненные родительским процессом. Если родительский процесс не вызывает эти функции вовремя, информация о состоянии дочернего процесса не может быть удалена из ядра, что приводит к тому, что процесс остается в состоянии «зомби». Попытка удалить зомби-процесс с помощью kill -9 неэффективна, поскольку он не занимает ресурсов CPU или памяти, а лишь сохраняет номер процесса (PID) и небольшое количество информации о состоянии.

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

Причина появления процесс-зомби

Наиболее распространенная причина возникновения зомби-процесса:

  • Родительский процесс не успевает обработать информацию о завершении дочернего процесса, что приводит к его переходу в «зомби-состояние».

В этой статье будет рассмотрен пример на основе PostgreSQL.

Решение для состояния «t»

Когда главный процесс PostgreSQL находится в состоянии «t» (отслеживается и остановлен), можно использовать отладчик gdb, чтобы удержать его. Если в этот момент убить дочерний процесс, он станет зомби-процессом.

81d738e9662c84084991b47e1b24d749.jpg

Клиентские процессы, которые находятся в состоянии записи, также будут продолжать работу, в результате чего файлы WAL (Write Ahead Log) будут расти. В это время основное состояние процесса находится в состоянии «t».

Чтобы восстановить нормальное состояние PostgreSQL, можно использовать команду:

ps -ef | grep 1797  # Для проверки процесса PostgreSQL
kill           # Для завершения процесса

После этого дочерние процессы будут перезапущены, а состояние главного процесса вернется в «S».

db2a7ad5998735191b528c5577689120.jpg

Решение для состояния «t»

Состояние «t» указывает, что процесс остановлен. Чтобы исправить это, можно выполнить следующие действия:

  1. Использовать kill -19 , чтобы остановить главный процесс.

  2. Затем завершить все дочерние процессы с помощью kill -9.

10106db545d21a3054ba8150babd531c.jpg

При этом состояние родительского процесса станет «t», и он не сможет обрабатывать сообщения о завершении дочернего процесса. Чтобы возобновить работу родительского процесса, можно отправить команду продолжения: kill -18

Это позволит родительскому процессу снова начать обработку сигналов.

6b0c493f8e180823407bab02d832a845.jpg

Когда процесс завершен, но родительский процесс еще не обработал его статус завершения, он становится зомби-процессом.

86d6f76510e6b513ef1b75236071105f.jpg

Важно отметить, что в вышеупомянутых состояниях дочерние процессы также могут находиться в состоянии «Z». Если состояние родительского процесса нормальное, но дочерний процесс «Z», то причины возникновения зомби-процесса становятся трудно отслеживаемыми.

Симуляция зомби-процесса

Для симуляции процесса, при котором родительский процесс не обрабатывает информацию о завершении дочернего процесса, можно создать скрипт zombie_process.py со следующим содержимым:

import os
import time

def create_zombie():
    pid = os.fork()  # Создаем дочерний процесс
    if pid > 0:
        # Родительский процесс: не обрабатывает завершение дочернего процесса
        print(f"Родительский процесс PID: {os.getpid()}")
        print(f"Дочерний процесс PID: {pid}")
        print("Дочерний процесс становится зомби (родитель не собирает статус).")
        time.sleep(60)  # Родительский процесс спит, чтобы сохранить дочерний процесс в состоянии зомби
    elif pid == 0:
        # Дочерний процесс
        print(f"Дочерний процесс PID: {os.getpid()} завершен")
        os._exit(0)  # Завершаем дочерний процесс

if __name__ == "__main__":
    create_zombie()

Запустите этот скрипт с помощью:

python3 zombie_process.py

В результате дочерний процесс будет находиться в состоянии «Z», а родительский процесс будет в нормальном состоянии. Чтобы избавиться от зомби-процесса, можно убить родительский процесс, чтобы управление перешло к системному процессу systemd, который обработает статус завершения зомби-процесса.

© Habrahabr.ru