L'optimisation des performances d'Apache Airflow fait passer les équipes d'un problème observé à un résultat vérifié. Commencez par identifier la version installée, la topologie de déploiement, les prérequis et le composant exact à inspecter. Cet article s'adresse aux développeurs, consultants DevOps et équipes techniques de startups qui doivent relier le réglage d'Airflow, l'optimisation, la réduction de la latence et l'élimination des goulets d'étranglement à des commandes concrètes, des sorties attendues, des signaux de défaillance et des décisions de récupération. L'objectif est la sécurité opérationnelle : observer avant de changer, limiter le rayon d'impact, utiliser des valeurs de remplacement au lieu de secrets, vérifier le résultat et documenter comment récupérer si l'état attendu n'est pas atteint.
Inventaire de la version et de l'environnement
Avant toute modification, capturez l'état actuel avec des horodatages. Enregistrez la version d'Airflow (2.x ou 3.x), le type d'exécuteur (LocalExecutor, CeleryExecutor, KubernetesExecutor ou CeleryKubernetesExecutor), le moteur et la version de la base de données de métadonnées (PostgreSQL 13+, MySQL 8+), la méthode de distribution des DAG (GitSync, images précuites ou montages de volumes), les packages fournisseurs installés avec leurs versions, et la plateforme de déploiement (Docker Compose, Kubernetes via Helm, service géré tel que MWAA ou Cloud Composer). Dans Airflow 3, l'architecture se divise en un serveur API et un processeur de DAG distinct, donc la portée de la version affecte directement les composants à inspecter.
Exécutez d'abord des vérifications de santé en lecture seule. Pour Airflow 3, interrogez GET /api/v2/monitor/health et examinez individuellement les champs metadatabase, scheduler, dag_processor et triggerer -- ne considérez pas le code HTTP 200 comme une preuve que chaque composant est sain. Pour Airflow 2, utilisez airflow jobs check --job-type SchedulerJob --hostname $(hostname) --allow-multiple pour vérifier les battements de cœur du planificateur, et airflow db check (ou airflow db check-migrations) pour confirmer la connectivité de la base de données de métadonnées et l'état des migrations. Capturez la sortie de airflow version, pip list | grep -E "apache-airflow|provider", et votre configuration spécifique à l'exécuteur (par exemple, airflow config get-value celery worker_concurrency ou kubectl get pods -n airflow -l component=scheduler). Stockez cet inventaire dans un fichier daté ; il devient votre base de référence pour la vérification de restauration.
Chemin de configuration sécurisé
Appliquez le plus petit changement justifié à un composant ciblé à la fois. Pour le planificateur, les leviers courants incluent scheduler.min_file_process_interval (par défaut 30s ; augmenter à 60s pour de gros ensembles de DAG afin de réduire l'UC), scheduler.parsing_processes (à faire correspondre aux cœurs d'UC, généralement 2-4), et scheduler.max_tis_per_query (par défaut 512 ; augmenter à 1024 si vous voyez des avertissements "max TIs per query" dans les journaux). Pour la base de données de métadonnées, assurez-vous que sql_alchemy_pool_size et sql_alchemy_max_overflow sont dimensionnés pour votre concurrence : un point de départ typique est pool_size=10, max_overflow=10 pour CeleryExecutor avec 20 workers, puis ajustez proportionnellement. Pour KubernetesExecutor, réglez kubernetes.worker_pods_creation_batch_size (par défaut 1) à 5-10 pour réduire la pression sur le serveur API lors des pics de planification.
Effectuez les changements dans votre couche de gestion de configuration (valeurs Helm, surcharge Docker Compose ou groupe de paramètres de service géré) plutôt que d'éditer airflow.cfg directement sur un pod en cours d'exécution. Déployez le changement sur un environnement de staging d'abord. Vérifiez le résultat avec une vérification ciblée : après avoir augmenté parsing_processes, lancez airflow jobs check --job-type SchedulerJob --limit 100 et confirmez que les horodatages latest_heartbeat progressent sans à-coups sur tous les processus d'analyse. Après avoir ajusté les paramètres du pool de base de données, exécutez un DAG représentatif avec 50 tâches concurrentes et surveillez l'absence d'OperationalError: pool exhausted dans les journaux du planificateur -- l'absence de cette erreur sous charge confirme que le pool est adéquat. Enregistrez la différence de configuration, l'horodatage de déploiement et la sortie de vérification.
Vérification et diagnostics
Établissez une boucle de vérification reproductible. Pour le débit du planificateur, mesurez la latence d'analyse des DAG : grep "DAG parsing took" $AIRFLOW_HOME/logs/scheduler/latest/*.log | tail -20 doit afficher des temps constants sous la seconde pour des DAG simples. Si l'analyse dépasse 5 secondes, activez scheduler.enable_health_check_server = True (Airflow 2.5+) et interrogez http://scheduler:8080/health pour la charge utile dag_processing, qui rapporte last_parsing_time et parsing_failures. Pour la latence de mise en file d'attente des tâches, interrogez directement la base de données de métadonnées :
SELECT
dag_id,
task_id,
execution_date,
queued_dttm,
start_date,
EXTRACT(EPOCH FROM (start_date - queued_dttm)) AS queue_latency_seconds
FROM task_instance
WHERE state = 'running'
AND start_date > NOW() - INTERVAL '1 hour'
ORDER BY queue_latency_seconds DESC
LIMIT 20;
Une latence médiane de file d'attente supérieure à 30 secondes avec CeleryExecutor indique souvent une saturation du courtier (vérifiez la profondeur des files RabbitMQ/Redis) ou une famine des workers (vérifiez celery inspect active et celery inspect reserved). Pour KubernetesExecutor, lancez kubectl get pods -n airflow --field-selector=status.phase=Pending -l airflow-worker=true et comptez les pods bloqués en Pending au-delà de 60 secondes -- cela signale des problèmes de capacité de cluster ou de classe de priorité.
Instrumentez l'observabilité au niveau des DAG en ajoutant un on_execute_callback qui émet une métrique personnalisée (Prometheus Histogram ou timing StatsD) capturant task_instance.duration. Comparez le 95e percentile de durée avant et après chaque itération de réglage. Si vous n'avez pas de pile de métriques, utilisez le airflow tasks test intégré avec --dry-run pour valider la correction de l'analyse des DAG sans effets de bord, et airflow dags trigger --run-id manual_$(date +%s) <dag_id> pour générer une exécution contrôlée pour l'échantillonnage de latence.
Modes de défaillance et récupération
Documentez le mode de défaillance, le signal de détection et les étapes de récupération pour chaque levier de réglage.
| Leviers de réglage | Mode de défaillance | Signal de détection | Étapes de récupération |
|---|---|---|---|
parsing_processes > cœurs UC | Arrêt OOM du planificateur, blocage de l'analyse | dmesg montre le tueur OOM ; airflow jobs check montre des battements de cœur obsolètes > 5 min | Rétablir parsing_processes ; redémarrer le planificateur via systemctl restart airflow-scheduler ou kubectl rollout restart deployment/airflow-scheduler |
sql_alchemy_pool_size trop élevé | Épuisement des connexions à la base de données | psql -c "SELECT count(*) FROM pg_stat_activity WHERE state='active';" atteint max_connections ; les instances de tâche échouent avec OperationalError | Réduire pool_size et max_overflow ; lancer airflow db check ; redémarrer le planificateur et le serveur web |
worker_concurrency > mémoire worker | OOM worker, tâche KILLED par le noyau | Journaux worker montrent MemoryError ou Code de sortie 137 ; celery inspect stats montre pool.max-concurrency en baisse | Baisser worker_concurrency ; s'assurer que resources.limits.memory dans Kubernetes dépasse worker_concurrency * mémoire_estimée_tâche |
Timeout dag_processor (Airflow 3) | DAG bloqués en état parsing | GET /api/v2/monitor/health montre dag_processor.status: unhealthy ; last_parsing_time obsolète | Augmenter dag_processor.timeout ; vérifier la complexité du DAG ; redémarrer le pod du processeur de DAG |
Pour tout changement, la vérification de récupération est un airflow jobs check --job-type SchedulerJob réussi (tous les battements de cœur dans les 60 secondes) et un airflow db check propre dans les cinq minutes suivant la restauration. Conservez un guide d'exploitation avec les valeurs Helm exactes ou le fichier de surcharge Compose représentant le dernier état connu bon.
Liste de contrôle opérationnelle
Utilisez cette liste avant et après chaque cycle de réglage :
- [ ] Inventaire capturé :
airflow version, exécuteur, base de données, fournisseurs, méthode de déploiement, horodaté dansinventaire_$(date +%Y%m%d_%H%M).txt - [ ] Métriques de base enregistrées : latence d'analyse du planificateur (médiane, p95), latence de file d'attente des tâches (médiane, p95), durée d'exécution des DAG (p50, p95) pour trois DAG représentatifs
- [ ] Changement de configuration unique mis en scène dans le contrôle de version avec message de commit descriptif (ex. : "Augmenter scheduler.parsing_processes de 2 à 4 pour nœuds 8 cœurs")
- [ ] Changement déployé sur le staging ; vérifications de santé réussies (
/api/v2/monitor/healthtout vert ouairflow jobs checkpropre) - [ ] Test de charge exécuté : déclencher 10 exécutions DAG concurrentes de la suite représentative ; capturer les métriques pendant 15 minutes
- [ ] Métriques comparées à la base ; amélioration confirmée ou régression documentée
- [ ] Changement promu en production avec les mêmes étapes de vérification
- [ ] Plan de restauration validé :
git revert <commit>; helm upgrade --install ...ou équivalent se termine en moins de 10 minutes - [ ] Inventaire post-changement capturé et comparé à la base
Conclusion
L'optimisation des performances d'Apache Airflow ne produit des résultats fiables que lorsque chaque recommandation est adaptée à la version, observable et réversible. Copier un extrait de configuration sans vérifier les prérequis, mesurer le comportement de base et définir un chemin de restauration vérifié n'est pas une procédure d'exploitation -- c'est du travail au doigt mouillé. Comme prochaine étape, choisissez une vérification à faible risque dans cet article : capturez votre latence d'analyse du planificateur actuelle, ajustez scheduler.parsing_processes pour qu'elle corresponde à vos cœurs d'UC, déployez sur le staging et mesurez le changement sous un test de charge contrôlé. Enregistrez les chiffres avant-après, confirmez que la restauration fonctionne, et seulement alors promouvez en production. Un flux de travail technique fiable rend l'échec visible, protège les valeurs sensibles, limite les changements à la ressource visée et définit la vérification de récupération avant qu'un incident ne force la décision.