← Назад к вопросам

В чем разница между Cron и Airflow?

2.0 Middle🔥 121 комментариев
#DevOps и инфраструктура#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Cron vs Airflow: сравнение систем планирования задач

Это хороший вопрос, потому что выбор между ними зависит от сложности задач. Расскажу о различиях и когда какой использовать.

Что такое Cron

Cron — это встроенный в Unix/Linux планировщик задач, который запускает команды по расписанию.

Простой пример Cron

# Добавить в crontab
crontab -e

# Запускать Python скрипт каждый день в 3:00 утра
0 3 * * * /usr/bin/python3 /home/user/backup.py

# Запускать каждые 15 минут
*/15 * * * * /home/user/update_cache.sh

# Запускать в понедельник в 9:00
0 9 * * 1 /home/user/weekly_report.py

Формат crontab:

┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
│ │ │ │ │
│ │ │ │ │
0 3 * * * /path/to/script.py

Что такое Airflow

Apache Airflow — это платформа для программного определения, планирования и мониторинга рабочих процессов (DAGs — Directed Acyclic Graphs).

Простой пример Airflow

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

def extract_data():
    print("Extracting data...")

def transform_data():
    print("Transforming data...")

def load_data():
    print("Loading data...")

# Определяем DAG (направленный ациклический граф)
default_args = {
    'owner': 'airflow',
    'retries': 1,
    'retry_delay': timedelta(minutes=5),
    'start_date': datetime(2024, 1, 1),
}

dag = DAG(
    'etl_pipeline',
    default_args=default_args,
    description='ETL pipeline',
    schedule_interval='0 3 * * *',  # Каждый день в 3:00
)

# Задачи
extract_task = PythonOperator(
    task_id='extract',
    python_callable=extract_data,
    dag=dag,
)

transform_task = PythonOperator(
    task_id='transform',
    python_callable=transform_data,
    dag=dag,
)

load_task = PythonOperator(
    task_id='load',
    python_callable=load_data,
    dag=dag,
)

# Зависимости (порядок выполнения)
extract_task >> transform_task >> load_task

Визуальное сравнение

╔════════════════════════════════════════════════════════╗
║                     CRON                               ║
╠════════════════════════════════════════════════════════╣
║ 0 3 * * * /usr/bin/python3 /home/backup.py             ║
║                                                        ║
║ 3:00 AM → run backup.py                               ║
║                                                        ║
║ [Script works or fails] ← No visibility                ║
║                                                        ║
║ Done (success/error lost in logs)                     ║
╚════════════════════════════════════════════════════════╝

╔════════════════════════════════════════════════════════╗
║                   AIRFLOW                              ║
╠════════════════════════════════════════════════════════╣
║ DAG: etl_pipeline                                      ║
║                                                        ║
║ 3:00 AM ↓                                              ║
║   [extract_data] ← Task 1                             ║
║         ↓ (success)                                    ║
║   [transform_data] ← Task 2                           ║
║         ↓ (success)                                    ║
║   [load_data] ← Task 3                                ║
║         ↓                                              ║
║   [Status: Success] ← Webui tracking                  ║
║                                                        ║
║ Full logs, metrics, alerts                            ║
╚════════════════════════════════════════════════════════╝

Таблица детального сравнения

АспектCronAirflow
СложностьПростой — одна командаСложный — DAGs с зависимостями
УстановкаВстроен в Unix/LinuxТребует установки (pip install apache-airflow)
КонфигурацияText файл (crontab)Python код (DAG файлы)
ЗависимостиНет — каждая задача независимаДа — задачи могут зависеть друг от друга
МониторингТолько логи и emailWebUI, метрики, alerts, сложный tracking
МасштабируемостьДо 100s задач1000s задач, распределённый
Retry логикаНужна своя в скриптеВстроена (retries, backoff)
Обработка ошибокManual — нужно ловить exit codesАвтоматическая — failed tasks, branching
Условное выполнениеНужна собственная логикаВстроено — branching, XCom
Управление зависимостямиManual управлениеЯвное определение (task >> task)
Data passingЧерез файлы или БДXCom (встроенный механизм)
История запусковТолько в логахПолная история в БД
ПараллелизмПоследовательныйПараллельный с управлением
ВерсионированиеПростая historyGit + Airflow version control

Практические примеры

Cron: когда подходит

Ситуация 1: Простой скрипт резервной копии

# Каждый день в 2:00 AM
0 2 * * * /usr/bin/python3 /scripts/backup_db.py >> /var/log/backup.log 2>&1

# Скрипт просто работает или падает
# Оповещение — через системный mail

Ситуация 2: Очистка старых файлов

# Каждый месяц в первый день
0 0 1 * * find /tmp -type f -mtime +30 -delete

Airflow: когда подходит

Ситуация 1: ETL пайплайн с зависимостями

# Нужно:
# 1. Загрузить данные из API
# 2. Трансформировать (зависит от 1)
# 3. Загрузить в БД (зависит от 2)
# 4. Создать отчёт (зависит от 3)
# + retry каждого шага отдельно
# + видеть прогресс в UI

В cron это невозможно элегантно сделать.

Ситуация 2: Сложный ML pipeline

DAG: model_training

├─ [fetch_data] 
│  └─ [preprocess_data]
│     ├─ [train_model_v1]
│     └─ [train_model_v2]  (параллельно)
│        └─ [evaluate_models]
│           ├─ [if v1 better] → deploy_v1
│           └─ [if v2 better] → deploy_v2
│              └─ [monitor_model]
└─ [notify_team]

Такой граф в cron — кошмар!

Ситуация 3: Data pipeline с error handling

with DAG('data_pipeline') as dag:
    # Если load_data падает, retry 3 раза
    load = PythonOperator(
        task_id='load_data',
        python_callable=load_from_api,
        retries=3,
        retry_delay=timedelta(minutes=5),
    )
    
    # Если load успешен, трансформировать
    transform = PythonOperator(
        task_id='transform',
        python_callable=transform_data,
    )
    
    # После трансформа отправить email с отчётом
    notify = EmailOperator(
        task_id='send_report',
        to=['team@company.com'],
    )
    
    load >> transform >> notify

Когда какой использовать

Используй Cron если:

  1. ✅ Одна простая задача (backup, clean cache)
  2. ✅ Нет зависимостей между задачами
  3. ✅ Нет сложной логики обработки ошибок
  4. ✅ Нужна минимальная инфраструктура
  5. ✅ Задача работает в одной системе
  6. ✅ Не нужен WebUI для мониторинга
# Простая задача — cron отлично подходит
0 * * * * python3 /scripts/update_cache.py

Используй Airflow если:

  1. ✅ Несколько взаимозависимых задач
  2. ✅ Сложная логика ветвления (if/else)
  3. ✅ Нужна автоматическая retry логика
  4. ✅ Нужно передавать данные между задачами
  5. ✅ Нужен мониторинг через WebUI
  6. ✅ Нужна история всех запусков
  7. ✅ Нужно параллельное выполнение
  8. ✅ Много задач (100+)
# Сложный пайплайн — Airflow необходим
load >> [transform, validate] >> merge >> load_db >> notify

Гибридный подход

На практике часто используют оба инструмента:

# Cron запускает Airflow DAG в определённое время
0 3 * * * curl -X POST http://localhost:8080/api/v1/dags/etl_pipeline/dagRuns

# Или используют Airflow с Cron-like schedule:
@dag(
    schedule_interval='0 3 * * *',  # Как в cron
)

Пример: миграция от Cron к Airflow

Было (Cron):

0 2 * * * python3 /scripts/data_sync.py
0 3 * * * python3 /scripts/generate_report.py
0 4 * * * python3 /scripts/cleanup.py

Проблемы:

  • Нет зависимостей
  • Если первый скрипт падает, второй запускается в пустую
  • Нет видимости
  • Нет автоматического retry

Стало (Airflow):

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

dag = DAG(
    'data_sync_pipeline',
    schedule_interval='0 2 * * *',
    start_date=datetime(2024, 1, 1),
)

sync_task = PythonOperator(
    task_id='sync_data',
    python_callable=sync_data,
    retries=3,
    dag=dag,
)

report_task = PythonOperator(
    task_id='generate_report',
    python_callable=generate_report,
    retries=2,
    dag=dag,
)

cleanup_task = PythonOperator(
    task_id='cleanup',
    python_callable=cleanup,
    dag=dag,
)

sync_task >> report_task >> cleanup_task

Преимущества:

  • Ясные зависимости
  • Если sync_task падает, остальные не запускаются
  • WebUI показывает статус
  • Автоматический retry каждого шага
  • История всех запусков

Резюме

КритерийВыбор
Одна простая задачаCron
Несколько независимых задачCron (или несколько cron entries)
Задачи с зависимостямиAirflow
Нужно передавать данные между задачамиAirflow
Нужна сложная retry логикаAirflow
Нужен мониторинг и историяAirflow
Много задач (100+)Airflow
Стартап, простой проектCron
Enterprise, сложные пайплайныAirflow

Практическая рекомендация:

  • Начни с Cron для простых задач
  • Когда сложность растёт и появляются зависимости — переходи на Airflow
  • Cron хорош для системного администрирования, Airflow — для data engineering и ML