Le fonctionnement asynchrone d'une chaîne ETL : optimisation et flexibilité
On extrait tout, on transforme tout, puis on charge tout. Dans une chaîne conçue ainsi, sans points de reprise ni isolement des erreurs, un seul enregistrement peut imposer de relancer un travail déjà terminé. C’est simple à dessiner sur un tableau blanc, et coûteux quand il faut reprendre à volume réel.
La question opérationnelle est simple : après un échec à 80 %, sait-on ce qui a été chargé, ce qui reste à faire et comment reprendre sans doubler les écritures ?
Le problème est l’absence de reprise
Un batch n’est pas nécessairement une transaction tout-ou-rien. Il peut traiter des blocs, conserver des points de reprise et isoler des rejets ; Spring Batch prévoit par exemple le redémarrage d’étapes interrompues. De même, « synchrone » ne veut pas forcément dire « attendre le lot entier » : SSIS peut transmettre les lignes au fil d’une transformation synchrone.
Le cas dangereux est le batch opaque : le rapport annonce un échec à 80 %, sans permettre d’identifier les écritures acquises ni de reprendre proprement. On repaie alors l’extraction et la transformation de données déjà bonnes. Un million d’enregistrements derrière un seul cas limite mal géré, et la fenêtre de bascule y passe.
L’asynchrone découple les étapes
Une architecture asynchrone avec files d’attente est une façon de découpler extraction, transformation et chargement. Chaque étape devient un poste distinct, relié aux autres par une file durable :
- l’extraction dépose les enregistrements dans une file, dans les limites de capacité prévues ;
- la transformation consomme cette file dès qu’un enregistrement est disponible, sans attendre que l’extraction soit finie ;
- le chargement prend le relais de la même façon, en aval.
Les étapes peuvent travailler en parallèle sur des enregistrements différents. Pendant que le dernier extrait arrive, les premiers peuvent déjà être chargés. Les opérations qui exigent un ensemble complet, comme certaines agrégations, et les dépendances entre objets conservent toutefois leurs points d’attente.
L’optimisation vient du parallélisme et de l’isolement
Découplé, chaque poste se dimensionne pour ce qu’il fait. La transformation est coûteuse en CPU ? On peut multiplier les consommateurs si le travail se partage. La cible limite les connexions ? On plafonne le chargement. La file absorbe un écart temporaire, mais le débit durable reste borné par le goulot : si l’amont produit davantage que l’aval ne consomme, le stock et le délai augmentent. Il faut surveiller la file et ralentir l’amont avant d’épuiser sa capacité — la contre-pression, ou backpressure. C’est la limite du lissage de charge par file d’attente.
Un rejet peut être isolé dans une file d’erreurs pendant que les objets indépendants avancent. Un article rejeté peut en revanche bloquer les lignes de commande qui le référencent : il faut suivre ces dépendances, puis libérer les enfants après validation du parent. La qualification record par record donne un verdict individuel ; elle ne supprime pas les relations entre objets.
La flexibilité vient de la même rupture
Le découplage facilite les changements, à condition de câbler le bon parcours. Des consommateurs concurrents sur une même file se répartissent le travail : ils servent à augmenter la capacité d’une étape. Un enrichissement obligatoire doit être placé avant le chargement, qui consomme sa sortie. Une seconde cible devant recevoir les mêmes données demande une diffusion vers des files ou abonnements distincts, selon le modèle publication-abonnement. Elle ne doit pas prendre une partie des messages destinés à la première.
Le rejeu se prépare lui aussi. Il faut conserver les entrées et les versions de règles, identifier le périmètre affecté par une correction, y compris ses dépendances, puis réappliquer les changements dans l’ordre requis. Une livraison peut être répétée : les écritures doivent être idempotentes, par exemple grâce à une clé stable et une mise à jour contrôlée. Il faut aussi empêcher un ancien état rejoué d’écraser un état plus récent. Une file ne garantit à elle seule ni ce résultat ni l’ordre de traitement avec plusieurs consommateurs.
Ce que ça change pour une migration
Une migration doit permettre de distinguer les données chargées, rejetées et en attente d’une dépendance. L’asynchrone facilite le découplage et la reprise ciblée ; un traitement batch muni des mêmes capacités de suivi et de redémarrage peut aussi soutenir les corrections successives.
C’est sur ces capacités que reposent les boucles Run / Fix de notre méthodologie. Le gain se mesure à la reprise : ce qu’on peut corriger et rejouer sans refaire inutilement le travail acquis, tout en conservant une cible cohérente. Les répétitions complètes restent nécessaires pour mesurer le parcours de bout en bout et la fenêtre de bascule.