Learning Platform
Глоссарий Troubleshooting
Урок 13.01 · 18 мин
Начальный
orchestrationDAGcrondependencies

В предыдущих модулях мы говорили о batch-job-ах, ETL/ELT, Spark, Kafka. У всех у них есть общее свойство: их нужно запускать — по расписанию или при наступлении условий. И когда таких job-ов десятки или сотни, простой cron перестаёт справляться. Тогда появляется потребность в оркестрации.

Этот урок — о том, почему оркестрация нужна, какие проблемы она решает и почему DAG стал универсальной абстракцией. Конкретные инструменты (Airflow, Dagster, Prefect) — в следующих уроках.

Начинаем с cron

Большинство DE начинали с cron. У тебя есть Linux-сервер, и в /etc/crontab ты пишешь:

0 4 * * * python /opt/etl/load_orders.py
0 5 * * * python /opt/etl/load_customers.py
0 6 * * * python /opt/etl/build_marts.py

Каждый день в 04:00, 05:00, 06:00 запускаются три скрипта. Сначала загружаются заказы, потом клиенты, потом строятся витрины. Это работает.

Пока у тебя 3 скрипта. Когда их становится 30, появляются проблемы.

Проблема 1: зависимости

В реальной аналитике job-ы зависят друг от друга. Витрина fct_orders_summary нужна после того, как загружены и orders, и customers, и products. Если витрина запустилась раньше времени — она построится на старых данных или сломается с ошибкой.

В cron ты пытаешься решить это временем:

0 4 * * * python load_orders.py
0 4 * * * python load_customers.py
0 4 * * * python load_products.py
0 6 * * * python build_summary.py  # надеемся, что к 6 утра всё успело

«Надеемся» — ключевое слово. Если load_orders.py вчера упал, его перезапустили вручную в 5:30, и к 6 утра не успело — build_summary запустится на неполных данных. И ты узнаешь об этом из жалоб бизнеса утром.

Cron не знает про зависимости

Cron запускает по времени. Если предыдущий шаг упал или задержался — следующий просто стартует в своё время, не дождавшись.

04:00load_ordersКаждый день в 04:00 пытается загрузить заказы. Иногда падает из-за временной недоступности источника.
04:00load_customers
04:00load_products
06:00build_summaryЗапускается строго в 06:00. Если кто-то из upstream упал — стартует на неполных данных или ломается.
Если load_orders упалОдин из источников был недоступен с 03:50 до 05:30.
cron не знает
06:00 build стартуетна старых данныхbuild_summary запустится на старых данных load_orders, потому что cron не отслеживает зависимости.

Проблема 2: retries

Job упал — что делать? В cron — ничего, до следующего запуска по расписанию. То есть утром, через сутки.

Иногда падения транзиентные: source-API не отвечал 30 секунд из-за deploy, потом восстановился. Перезапустил бы job через 5 минут — всё бы заработало. В cron этого механизма нет. Надо писать руками в скрипте или ставить будильник на ручной перезапуск.

Проблема 3: observability

В cron job упал — куда уйдут логи? >> /tmp/log.txt 2>&1 в строчке cron. Дальше эти логи разбросаны по серверам, не агрегированы, не структурированы.

Когда у тебя 100 cron-job-ов, ты не знаешь:

  • Какие сегодня успешно отработали? Какие упали? Какие даже не запустились?
  • Сколько времени каждый занимает? Растёт ли время?
  • Какие job-ы давно никто не трогал и могут уже не работать?

Без observability ты узнаёшь о проблемах от бизнеса. «Почему дашборд сегодня пустой?» — и начинается час разборок.

Проблема 4: backfill

Бизнес говорит: «В нашей логике расчёта retention был баг. Перепроцессите данные за последние 3 месяца с новой логикой». В cron у тебя нет механизма этого сделать. Надо вручную писать скрипт, который проходит по датам, запускает job для каждой, отслеживает успешные и упавшие, перезапускает упавшие. И снова — никакой observability.

В оркестраторе это команда airflow dags backfill --start-date 2026-02-17 --end-date 2026-05-17 my_dag — и за минуту запустилось 90 параллельных runs, observability в UI, retry на упавшие.

Что такое DAG

В оркестраторах фундаментальная абстракция — это DAG (Directed Acyclic Graph) — направленный ациклический граф. По-русски: набор узлов (задач) и стрелок (зависимостей) между ними, причём нет циклов.

DAG: задачи и зависимости

Узлы — задачи. Стрелки — зависимости. Граф направленный (стрелки имеют направление) и ациклический (нет петель). Это базовая абстракция оркестрации.

load_orderstaskЗадача загрузки заказов из источника в raw-слой DWH.
build_summarytaskЗадача построения сводной витрины. Зависит от трёх load-task.
load_customerstask
load_productstask

В этом DAG:

  • Три задачи (load_orders, load_customers, load_products) могут выполняться параллельно — они независимы.
  • build_summary имеет зависимость от всех трёх и стартует только после успеха всех upstream.
  • Граф ациклический — нет ситуации «A зависит от B, B зависит от A».

Оркестратор берёт этот DAG, разбирает зависимости, и сам решает, что запускать когда. Если load_orders упал — build_summary не стартует, потому что upstream не завершён. Тут не «надеемся», тут гарантия.

Что даёт оркестратор

Управление зависимостями. DAG автоматически решает, когда что запускать. Если зависимости не выполнены — задача ждёт.

Retries. Каждой задаче можно задать retries=3, retry_delay=5min. Упала — повторим через 5 минут, до 3 раз, потом alert.

Observability. UI показывает все запуски: успешные, упавшие, в процессе. Логи каждой задачи доступны кликом. Метрики времени выполнения, success rate, SLA.

Backfill. Команда «прогнать DAG за последние 90 дней» — встроенная функциональность.

Расписание. Cron-выражение или более сложные триггеры (sensor по приходу файла, event в Kafka).

Параметризация. Один и тот же DAG запускается для разных дат, разных регионов, разных конфигураций.

Alerting. Интеграция со Slack/Email/PagerDuty при падении или нарушении SLA.

NOTE

Оркестратор — это control plane DE-инфраструктуры. Он сам не обрабатывает данные (это делают Spark, dbt, Python-скрипты), но координирует, что запускать когда и в каком порядке. Без оркестратора в production-DE далеко не уедешь.

Pipeline на оркестраторе vs cron

Сравним: тот же сценарий «ежедневная загрузка и построение витрины» в cron и в оркестраторе.

Cron:

# /etc/crontab
0 4 * * * python /opt/etl/load_orders.py
0 4 * * * python /opt/etl/load_customers.py
0 4 * * * python /opt/etl/load_products.py
0 6 * * * python /opt/etl/build_summary.py

Минусы: нет зависимостей, нет retries, нет observability, нет backfill.

Airflow DAG (псевдокод):

with DAG(
    'daily_summary',
    schedule_interval='0 4 * * *',
    retries=2,
    retry_delay=timedelta(minutes=5),
    sla=timedelta(hours=2),
):

    load_orders = PythonOperator(
        task_id='load_orders',
        python_callable=load_orders_fn,
    )

    load_customers = PythonOperator(
        task_id='load_customers',
        python_callable=load_customers_fn,
    )

    load_products = PythonOperator(
        task_id='load_products',
        python_callable=load_products_fn,
    )

    build_summary = PythonOperator(
        task_id='build_summary',
        python_callable=build_summary_fn,
    )

    [load_orders, load_customers, load_products] >> build_summary

В одном файле описаны: расписание, retries, SLA, задачи, зависимости. Airflow исполняет всё остальное: запускает по расписанию, ретраит упавшие, ждёт зависимости, шлёт алерты при нарушении SLA, показывает в UI.

Когда cron всё-таки достаточно

Не надо ставить Airflow ради двух скриптов. Cron подходит, когда:

  • 1-5 простых job-ов без зависимостей.
  • Падения редки, ручной перезапуск ок.
  • Команда из 1-2 человек, кто-то всегда in-charge.
  • Нет требований к observability.

Когда переходить:

  • 10+ job-ов с зависимостями.
  • Backfill требуется регулярно.
  • Команда из 3+ человек должна видеть состояние пайплайнов.
  • SLA важны (отчёт CFO к 9 утра).
  • Хочется retry, alerting, метрики.
Airflow: scheduler, executor, worker — как устроена оркестрация изнутри
TIP

Многие команды откладывают переход с cron на Airflow слишком долго и страдают. Но и обратное — поднимать Airflow ради 3 скриптов — пустая трата времени. Хорошая инженерная гигиена — выбрать инструмент под объём задачи.

Попробуй сам

Подумай о любом аналитическом пайплайне, который ты видел. Найди в нём зависимости (что от чего зависит). Нарисуй мысленно DAG. Какие задачи могут выполняться параллельно? Какая критическая цепочка от source до конечной витрины? Это упражнение — обычная работа DE при проектировании пайплайнов.

Проверка знанийKnowledge check
Почему DAG (направленный ациклический граф) стал универсальной абстракцией для оркестрации, и какие четыре главные проблемы он решает по сравнению с cron?
ОтветAnswer
DAG позволяет явно выразить зависимости между задачами: какая задача стартует после успешного выполнения каких других. Граф направленный (стрелки имеют направление) и ациклический (нет циклов A->B->A) — это математически гарантирует, что выполнение имеет корректный порядок. Четыре главные проблемы, которые DAG решает по сравнению с cron: 1) зависимости — задача стартует только после всех upstream, не по таймеру; 2) retries — упавшие задачи автоматически перезапускаются с настраиваемым delay; 3) observability — UI показывает состояние всех runs, логи, метрики, SLA; 4) backfill — команда «прогнать DAG за исторический период» встроена и распараллеливается. Cron всех этих свойств не имеет.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Что такое DAG в контексте оркестрации пайплайнов?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4