Хотя Apache AirFlow считается достаточно зрелой платформой оркестрации рабочих процессов, при практическом использовании этого фреймворка дата-инженер может столкнуться с некоторыми сложностями. Одной из таких проблем являются так называемые «зомби-задачи». Разбираемся, чем они опасны, и как от них избавиться.
Что такое зомби-задачи и чем они опасны
В Unix-подобных операционных системах есть понятие процесса-зомби, который фактически завершился через системный вызов выхода, но все еще имеет запись в таблице процессов, находясь в завершенном состоянии (Terminated state). В отличие от обычных процессов, команда kill не влияет на зомби-процесс. Зомбирование происходит для дочерних процессов, где запись по-прежнему необходима, чтобы позволить родительскому процессу прочитать статус выхода своего дочернего элемента. Как только статус выхода прочитан с помощью системного вызова ожидания, запись зомби-процесса удаляется из таблицы процессов. Дочерний процесс всегда сначала становится зомби-процессом, а затем удаляется из таблицы ресурсов. В большинстве случаев при нормальной работе системы зомби-процессы вызывают утечку ресурсов, хотя единственный ресурс, который они занимают, это идентификатор процесса.
Таким образом, зомби-задачи – это процессы, которые были завершены, но все еще присутствуют в таблице процессов. Такое встречается и в Apache AirFlow, распределенной среде, где контейнеры задач выполняются на общих хостах. Если произошло неожиданное завершение выполнения задачи, в логах AirFlow она может превратиться в зомби, будучи фактически завершенной, но по мнению планировщика она все выполняется. AirFlow может скорректировать состояние задачи-зомби, сделав ее завершенной или неудачной, но это отразится на всей цепочке DAG. Все последующие задачи или задачи в очереди после выполнения зомби-задачи не смогут выполниться, даже если реализовано динамическое изменение DAG, о чем мы мы писали здесь.
Зомбирование может произойти, когда задача завершает выполнение, но рабочий процесс AirFlow завершается, прежде чем он пометил задачу как «успешную» или «неудачную». В результате задача остается в состоянии «выполняется». Важно отметить, что зомби-задачи — это не то же самое, что «тупиковые» задачи, которые застревают в бесконечном цикле и не могут выполняться. Зомби-задачи завершили свое выполнение, но не были должным образом отмечены как завершенные в базе данных метаданных AirFlow.
Зомби-задачи могут иметь ряд негативных последствий для конвейеров обработки данных:
- затрудняют мониторинг и отладку, увеличивая список задач и мешая дата-инженеру увидеть, какие задачи на самом деле выполняются;
- блокируют выполнение нижестоящих задач. Если задача имеет задачу-зомби в качестве зависимости, она не сможет работать, пока задача-зомби не будет решена. Это приводит к задержкам в конвейерах обработки данных и снижает их эффективность.
- снижают точность статуса конвейера обработки данных. Если задача помечена как «выполняется», но на самом деле завершена, может создаться впечатление, что конвейер все еще выполняется, когда он на самом деле завершен. Это может запутать дата-инженера и затруднить понимание состояния конвейеров.
Пользовательский интерфейс администратора AirFlow позволяет найти зомби-задачи, которые могут влиять на запуск DAG, препятствуют выполнению нижестоящих задач или поставленных в очередь. Если на запуск DAG влияют задачи-зомби, то он всегда находится в состоянии выполнения, но входящие в него задачи не выполняются задачи, а также поставленные в очередь или нижестоящие задачи, постоянно ожидают выполнения.
Можно справиться с задачами-зомби, вручную пометив их как «успешные» или «неудачные» в GUI AirFlow на странице «Экземпляры задач». Но это может занять много времени и довольно непрактично в производственной среде, где одновременно работает много конвейеров. Другие, более эффективные способы борьбы с зомби-задачами мы рассмотрим далее.
Как бороться с зомби-задачами в Apache AirFlow
Рассмотрим влияние зомби-задач на практическом примере. Например, планировщик добавляет задачу в очередь исполнителей для запуска оператора пода Kubernetes в пуле узлов. Один из рабочих узлов берет задачу и инициализирует ее экземпляр. Если, к примеру, из-за помех на линии передачи данных или локального сбоя узла кластера, worker не может отправить heartbeat-сигнал в БД в течение интервала, большего чем значение конфигурации scheduler_zombie_task_threshold, то планировщик помечает задачу как зомби.
Избежать сбоев из-за зомби-задач помогут следующие рекомендации:
- увеличить параметр повтора для краткосрочных задач, задав его больше 1. Обычно достаточно 2-4 попытки. Следует установить количество повторных попыток в аргументе default_arg, чтобы они применялись на уровне DAG и были более детализированы для конкретных задач только там, где это необходимо.
- повысить значение конфигурации планировщика scheduler_zombie_task_threshold с 5 минут по умолчанию до 20–30 минут для длительных задач, т.к. в этом случае вероятность того, что задача может быть помечена как зомби, возрастает. Особенно это характерно для некоторых специфических операторов AirFlow, таких как KubernetesPodOperator.
- также для длительных задач следует убедиться, что они не потребляют ресурсы рабочего узла. Если это случилось, лучше запустить длительную задачу в другом пуле узлов Kubernetes с помощью KubernetesPodOperator;
- для задач, использующих поды Kubernetes, полезно вести журнал непрерывно с интервалом меньше, чем scheduler_zombie_task_threshold, поскольку действия по регистрации подтвердят worker’у, что под работает;
- следует убедиться, что рабочий узел AirFlow имеет достаточно оперативной памяти и места на диске, иначе может произойти сбой, и задачи, запущенные на нем, будут помечены планировщиком как зомби вследствие сбоя.
Также можно использовать параметр zombie_max_age, который позволяет указать максимальный возраст для задач-зомби. Если задача помечена как выполняемая и не обновлялась в базе данных метаданных дольше указанного срока, она будет автоматически помечена как неудачная. Это может помочь предотвратить накопление зомби-задач и их влияние на конвейеры.
Ограничить количество зомби-задач можно следующими способами:
- установить значение параметра zombie_max_age в файле конфигурации AirFlow;
- написать собственный скрипт, который регулярно проверяет и разрешает зомби-задачи, используя API, который позволяет программно взаимодействовать с экземпляром AirFlow. Такой скрипт подключается к API Airflow, получает список всех задач, помеченных как выполняемые (в статусе running), и проверяет возраст каждой задачи. Задачи старше указанного периода можно пометить как неудачные (failed), чтобы завершить их.
Можно запланировать запуск этого скрипта на регулярной основе с помощью оператора BashOperator. Это обеспечит регулярную проверку и завершение задач-зомби, чтобы поддерживать бесперебойную работу конвейеров обработки данных в Apache AirFlow. Подробнее про управление жизненным циклом задачи в Apache AirFlow читайте в нашей новой статье. А как Kafka справляется со зомби-продюсерами, которые приводят к проблеме разделенного мозга в распределенной системе, вы узнаете здесь.
Узнайте больше про администрирование и эксплуатацию Apache AirFlow для дата-инженерии и аналитики больших данных на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:
Источники
- https://airflow.apache.org/docs/apache-airflow/stable/concepts/tasks.html
- https://medium.com/@gaurav.p2904/zombie-tasks-in-airflow-what-they-are-and-how-to-handle-them-d5d86c090204
- https://medium.com/@brihati1373/zombie-and-undead-tasks-in-airflow-e09ddbe6b22f
- https://resources.unizin.org/display/UDP/Zombie+tasks