Apache Airflow на собеседовании Data Engineer
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_datemax_active_runs— сколько одновременных run-ов разрешено для DAGtask_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 }}',
)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, идемпотентностью). На собесе спросят про реальный опыт.
Это официальная информация?
Нет. Статья основана на публичных источниках и опыте кандидатов.