В предыдущих модулях мы говорили о 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 запускает по времени. Если предыдущий шаг упал или задержался — следующий просто стартует в своё время, не дождавшись.
Проблема 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_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.
Оркестратор — это 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, метрики.
Многие команды откладывают переход с cron на Airflow слишком долго и страдают. Но и обратное — поднимать Airflow ради 3 скриптов — пустая трата времени. Хорошая инженерная гигиена — выбрать инструмент под объём задачи.
Попробуй сам
Подумай о любом аналитическом пайплайне, который ты видел. Найди в нём зависимости (что от чего зависит). Нарисуй мысленно DAG. Какие задачи могут выполняться параллельно? Какая критическая цепочка от source до конечной витрины? Это упражнение — обычная работа DE при проектировании пайплайнов.