Apache Airflow на собеседовании Data Engineer

Проверь себя · 1/3разбор после ответа
Вы сортируете товары по величине скидки discount по убыванию. Поле discount может быть NULL (скидки нет). Чтобы товары без скидки всегда оказывались внизу независимо от настроек СУБД, какой вариант сортировки выбрать?

Зачем Airflow на собесе DE

Airflow — стандарт оркестрации в большинстве российских IT-компаний. На собесе Data Engineer базовые знания Airflow ожидают по умолчанию: что такое DAG, как ставится зависимость между тасками, что такое идемпотентность.

Глубокие вопросы — для middle+:

  • Как работает scheduler и зачем catchup
  • В чём разница между PythonOperator и BashOperator при запуске одного и того же скрипта
  • Когда использовать sensor, а когда — пуллить из downstream
  • Как проектировать DAG, чтобы он переживал перезапуск с любого таска

DAG, операторы, зависимости

DAG (Directed Acyclic Graph) — направленный ациклический граф тасков. Главные элементы:

  • Operator — что делает таск (PythonOperator, BashOperator, KubernetesPodOperator и т.д.)
  • Task — экземпляр оператора в DAG
  • Dependencies — порядок выполнения, через >> или set_upstream/downstream

Минимальный DAG:

from airflow import DAG
from airflow.operators.python import PythonOperator
from datetime import datetime

with DAG(
  'simple_dag',
  start_date=datetime(2026, 1, 1),
  schedule='@daily',
  catchup=False,
) as dag:

  extract = PythonOperator(task_id='extract', python_callable=extract_fn)
  transform = PythonOperator(task_id='transform', python_callable=transform_fn)
  load = PythonOperator(task_id='load', python_callable=load_fn)

  extract >> transform >> load

Что важно знать на собесе:

  • schedule — cron-выражение или alias (@daily, @hourly)
  • catchup — если True, при первом запуске Airflow догонит все execution dates с start_date
  • max_active_runs — сколько одновременных run-ов разрешено для DAG
  • task_concurrency — сколько одновременных запусков одного таска

Идемпотентность и backfill

Идемпотентность — таск можно перезапустить с теми же параметрами и получить тот же результат. Без идемпотентности backfill не работает.

Пример неидемпотентного таска:

INSERT INTO events_agg (date, count)
VALUES ('2026-05-01', 10000);

При повторном запуске — дубликат. Идемпотентный вариант:

DELETE FROM events_agg WHERE DATE = '{{ ds }}';
INSERT INTO events_agg (DATE, count) ... ;

Или upsert с ON CONFLICT DO UPDATE. Или партиционированная таблица с INSERT OVERWRITE PARTITION.

Backfill — запуск DAG для прошлых execution dates. Используется, когда:

  • Нужно перегенерить данные после фикса бага
  • Догнать дни, когда DAG был выключен
  • Заполнить данные за период до запуска DAG

Команда:

airflow dags backfill -s 2026-01-01 -e 2026-01-31 my_dag

На собесе спросят: «Что произойдёт, если запустить backfill на DAG с неидемпотентными тасками?» Ответ: дубликаты, рассинхронизация, длительный дебаг.

XCom и шаблоны Jinja

XCom — механизм передачи данных между тасками. Ограничение — в дефолтном backend (БД) хранится только маленький JSON, для больших объёмов — кастомный backend.

def push_value(**context):
  context['ti'].xcom_push(key='user_count', value=12345)

def pull_value(**context):
  count = context['ti'].xcom_pull(key='user_count')

Jinja-шаблоны — встроены в большинство операторов. Главные переменные:

  • {{ ds }} — execution date в формате YYYY-MM-DD
  • {{ ds_nodash }} — то же без дефисов (для путей)
  • {{ ts }} — execution timestamp ISO
  • {{ macros.ds_add(ds, -7) }} — дата за 7 дней до execution

Используются в SQL-запросах, путях файлов, аргументах bash:

load = BashOperator(
  task_id='load',
  bash_command='spark-submit /jobs/etl.py --date={{ ds }}',
)
Готовишься к собесу Data Engineer?
Spark, Airflow, ClickHouse, SQL для DE — вопросы с разборами в Telegram
Тренировать DE в Telegram

Sensor-операторы

Sensor — ждёт условия, потом завершается. Используется когда зависимость от внешней системы (файл появился, таблица заполнена).

from airflow.sensors.filesystem import FileSensor

wait_file = FileSensor(
  task_id='wait_for_input',
  filepath='/data/input/{{ ds }}.csv',
  poke_interval=60,
  timeout=3600,
  mode='reschedule',
)

Главный антипаттерн — mode='poke' (по дефолту). Sensor занимает worker slot всё время ожидания. На длинных таймаутах это убивает кластер. Используйте mode='reschedule' — sensor освобождает slot между проверками.

Типичные задачи на собесе

1. Спроектировать DAG для ETL

Условие: «Каждый день забираем данные с API, трансформируем, кладём в DWH». Ответ должен включать:

  • Структуру: extract → transform → load
  • Идемпотентность: как работает повторный запуск
  • Обработку ошибок: retries, on_failure_callback
  • Алерты: SLA или callback в Slack

2. Дебаг сломанного DAG

Дают DAG-код с проблемой. Типичные баги: cyclic dependency, неправильный schedule, неидемпотентный таск, race condition между параллельными ветками.

3. Оптимизация медленного DAG

«У нас DAG из 50 тасков выполняется 4 часа. Как ускорить?» Ответ:

  • Параллелить независимые ветки
  • Группировать мелкие таски в один (TaskGroup)
  • Убрать неоправданные sensor-ы
  • Использовать KubernetesPodOperator для тяжёлых тасков
  • Профилировать конкретный таск

4. Архитектура мониторинга

Какие метрики важны: SLA по DAG, время выполнения каждого таска, количество ошибок, задержка scheduler. Где собирать (StatsD, Prometheus).

Частые ошибки

Бизнес-логика в DAG-файле. DAG-файл парсится scheduler каждые 30 секунд. Если в нём тяжёлый код (например, обращения к БД), это ломает scheduler.

Глобальные переменные в DAG. Между парсингами scheduler состояние не сохраняется. Используйте Airflow Variables или Connections, а не модульные переменные.

Sensor в poke-режиме на длинных таймаутах. Worker slot заблокирован, кластер деградирует.

XCom для больших данных. XCom хранится в БД метаданных. Для больших объёмов используйте S3/HDFS + только путь в XCom.

Не использовать catchup=False. При запуске DAG со start_date в прошлом по умолчанию запустит все пропущенные дни. Если этого не хотите — обязательно catchup=False.

FAQ

Какую версию Airflow учить?

Airflow 2.x. Версия 1.x устарела. На собесе спросят, что нового в 2.x: TaskFlow API, dynamic task mapping, dataset-driven scheduling.

Airflow vs Dagster vs Prefect — что выбрать?

Airflow — стандарт в РФ. Dagster и Prefect — современные альтернативы, иногда встречаются в стартапах. Для собеса — учите Airflow.

Сколько практики Airflow нужно для junior DE?

Один-два домашних проекта с боевым DAG (с sensor, XCom, идемпотентностью). На собесе спросят про реальный опыт.

Это официальная информация?

Нет. Статья основана на публичных источниках и опыте кандидатов.