Executors deep dive — обзор модуля
Executor — компонент, отвечающий за фактическое выполнение tasks. Он получает workload от scheduler, кладёт в свою queue/orchestrator, отслеживает результат. Этот модуль препарирует каждый executor 2.x до конкретных processes, threads и network calls.
Уроки модуля
| # | Урок | Что внутри |
|---|---|---|
| 01 | Обзор модуля | Текущий урок |
| 02 | LocalExecutor | multiprocessing.Queue, N worker processes, single-node limits |
| 03 | CeleryExecutor | Broker (Redis/RabbitMQ), prefetch pitfall, worker autoscaling |
| 04 | KubernetesExecutor | Pod-per-task, watcher thread, pod template, cold start mitigation |
| 05 | CeleryKubernetesExecutor / LocalKubernetesExecutor | Hybrid модели, routing через queue |
| 06 | Multiple Executors (AIP-61, 2.10+) | Несколько executors одновременно, task-specific routing |
| 07 | Executor comparison lab | Бенчмарки startup latency, throughput, cost trade-offs |
Executors доступные в 2.x
LocalExecutor
multiprocessing.Queue+ N worker процессов внутри scheduler-процесса- Best for: dev, single-node (<100 tasks/min)
- SequentialExecutor оставлен в 2.x только для testing (removed в 3.0)
CeleryExecutor
- Архитектура: Scheduler → Celery broker (Redis/RabbitMQ) → Workers → Result backend (Postgres)
worker_prefetch_multiplier(default 4) — pitfall: long-task занимает 4 slots, остальные voiding- Best practice:
worker_prefetch_multiplier = 1для long-task workloads celery_acks_late = True— ACK после успешного выполнения
KubernetesExecutor
- Pod-per-task → security isolation + dependency isolation
- Watcher thread в scheduler-процессе подписан на K8s API events
- Pod template overrides per-task через
executor_config={"pod_override": V1Pod(...)} - Cold start cost: 5-15s на pull image + scheduling + init container
CeleryKubernetesExecutor / LocalKubernetesExecutor (2.3+)
- Hybrid: по
queuetask выбирается путь queue="kubernetes"→ KE, остальное → Celery (или Local)- Use case: легковесные tasks на Celery (низкая latency), heavy/GPU на K8s (изоляция)
Multiple Executors (AIP-61, 2.10+)
С Airflow 2.10 можно конфигурировать несколько executors одновременно:
[core]
executor = LocalExecutor,CeleryExecutor,KubernetesExecutor
Первый — default. Task может явно указать:
@task(executor="KubernetesExecutor")
def gpu_inference():
pass
Это решает старую боль — раньше один Airflow = один executor. В 3.2 добавлено team-scoping (AIP-67).
Killer demos
- CeleryExecutor prefetch pitfall — long task (1h) + short tasks (1min) на одном worker. С
prefetch_multiplier=4show starvation, установить =1 → fix. - K8sExecutor cold-start measurement — измерить delay от submit до running, optimize через pre-pull image + minimal init container.
- Multiple Executors routing — DAG с light tasks (Celery) + heavy GPU tasks (K8s), увидеть как scheduler routes (AIP-61, 2.10+).
Comparison cheatsheet
| Executor | Task startup | Isolation | Best for |
|---|---|---|---|
| Local | Instant | Process | Dev, single-node |
| Celery | 1-3s | Worker concurrency | High throughput, low latency |
| Kubernetes | 10-30s | Full pod | Heavy resources, dependencies |
| CeleryKubernetes | Mixed | Per-task | Mixed workloads |
Что нового в 3.x (упоминание)
В Airflow 3.0 появился EdgeExecutor (AIP-69) — workers за NAT через HTTP polling. Это работает только с Task SDK boundary (AIP-72), которой нет в 2.x. Тема финального модуля upgrade path.