Aujourd’hui, les applications collectent une quantité infinie de données. De nombreuses applications doivent transformer ces données avant d’appliquer une logique métier significative. S’attaquer à ces données complexes ou à une tâche similaire gourmande en ressources processeur sans stratégie réfléchie peut avoir un impact élevé sur les performances. Cet article présente un modèle d’évolutivité (canaux et filtres) qui favorise la réutilisation et est approprié pour de tels scénarios.
Contexte du problème
Considérez un scénario où les données entrantes déclenchent une séquence d’étapes de traitement, où chaque étape rapproche les données de l’état de sortie souhaité. L’origine des données est appelée source de données. Des exemples de sources de données peuvent être des appareils IoT domestiques, un flux vidéo de caméras en bordure de route ou des mises à jour continues de l’inventaire des entrepôts. Les étapes de traitement au cours de la transformation exécutent généralement une opération spécifique et sont appelées filtres. Ces étapes de traitement sont indépendantes et n’ont pas d’effet secondaire ; c’est-à-dire que l’exécution d’une étape ne dépend d’aucune autre étape. Chaque étape de filtrage lit les données, effectue une opération de transformation basée sur les données locales et produit une sortie. Une fois que les données ont traversé les filtres, elles atteignent leur étape de traitement finale où elles sont consommées, appelées puits de données.
Une implémentation simple pourrait être un service complet qui prend l’entrée de données, exécute toutes les étapes de manière séquentielle et produit une sortie. Les modules du service effectuent l’étape requise et transmettent les données au module suivant. Bien que la solution semble initialement bonne car elle cache toute la complexité du traitement des données, l’utilisation d’un tel service monolithique présentera les problèmes énumérés :
- La solution limite la réutilisation du code.
- Toute modification d’une étape de traitement des filtres entraînera une libération de tous les filtres.
- L’étape de filtrage de traitement la plus lente peut devenir un goulot d’étranglement affectant le débit global du service.
- Au fur et à mesure que la solution évoluera, elle adaptera toutes les étapes de traitement. Une telle mise à l’échelle entraînera une utilisation excessive des ressources dans le cloud lorsque cela n’est pas prévu.
Ainsi, l’approche ci-dessus est inflexible, non évolutive et contre la réutilisabilité. Une bonne solution doit répondre à toutes les préoccupations ci-dessus. Essayons de trouver une solution à cela dans la section suivante.
Service monolithique avec modules de tâches
Solution
Nous pouvons améliorer la solution sous-optimale de la section précédente en divisant le service monolithique en une série de composants ou de fonctions, chacun effectuant une seule étape de filtrage de traitement. Ces fonctions sont combinées pour former un pipeline où les fonctions reçoivent une entrée standard et produisent une sortie acceptée. Une telle décomposition introduira un couplage lâche dans la solution. Cela permettrait le retrait, le remplacement, le réarrangement ou le branchement sans effort d’une nouvelle étape de filtrage dans les pipelines. De plus, cela permettra la réutilisation du code : si nous avons besoin d’un filtre de traitement similaire dans un autre pipeline, les filtres existants peuvent être partagés.
Solution tuyaux et filtres
La solution résout également le problème de l’étape de filtrage de traitement la plus lente qui constitue un goulot d’étranglement, car elle offre la possibilité de mettre à l’échelle des fonctions individuelles. La fonction la plus lente peut exécuter des instances parallèles pour répartir la charge et améliorer le débit. La mise à l’échelle individuelle des composants nous évitera également des coûts supplémentaires.
Mise à l’échelle individuelle de la solution de tuyaux et de filtres
Enfin, les filtres de traitement peuvent profiter de l’infrastructure cloud. Par exemple, nous pouvons demander une machine virtuelle spécifique en fonction du comportement d’un filtre, gourmand en processeur ou en mémoire.
Quand utiliser ce modèle
Comme nous avons maintenant une meilleure connaissance du modèle, cette section explore quand réfléchir au modèle.
- Le modèle est utile pour décomposer les workflows de traitement complexes où chaque étape est indépendante.
- Les étapes de traitement ont des besoins matériels ou des exigences d’évolutivité distincts et, dans certains cas, même des exigences de langage de programmation préférées.
- Le modèle peut résoudre les problèmes de flexibilité dans les flux de travail où les exigences et les processus métier changent constamment.
- Le modèle est efficace pour éliminer les goulots d’étranglement dans les flux de travail grâce au traitement parallèle et distribué des étapes individuelles.
Considérations importantes
Le modèle présente de nombreux avantages, mais considérez les points ci-dessous avant d’adopter ce modèle.
- La flexibilité accrue et la séparation claire se font au détriment de la complexité, en particulier lorsque les étapes de filtrage individuelles sont trop granulaires. De plus, le transfert de données et la communication entre les filtres est un surcoût.
- Il y a toujours un risque de perdre les messages entre les filtres ; par conséquent, une stratégie réfléchie est nécessaire pour atténuer ces scénarios.
- Comme ci-dessus, une stratégie de récupération est également nécessaire en cas de défaillance d’un pipeline. Un nouveau message peut-il être injecté dans le pipeline, ou existe-t-il une disposition pour enregistrer l’état du pipeline ?
- Chaque étape de filtre doit être sans état et avoir un contexte suffisant. Étant donné que ces étapes de filtrage fonctionnent de manière isolée, chaque filtre doit être doté de suffisamment d’entrées pour fonctionner.
Détails d’implémentation
Plusieurs implémentations du modèle sont possibles en fonction de la nature de la solution.
Comportement dynamique du pipeline
Stratégie axée sur les données: Elle est également connue sous le nom de stratégie push. La source de données écrit un message dans le pipeline. Les filtres lisent le message entrant, le traitent et le poussent plus loin. Enfin, le message atteint le puits de données, où il est consommé.
Stratégie axée sur la demande: Une stratégie axée sur les données pousse le message à travers le pipeline, tandis que dans une stratégie axée sur la demande, un message est extrait. Chaque fois que le récepteur de données lance une lecture, la source de données produit un nouveau message. Les filtres traitent ensuite le nouveau message et le résultat final transformé est envoyé au puits de données en réponse à l’appel d’origine.
Comportement de pipeline dynamique des canaux et des filtres
Comportement des messages
Au cours des discussions jusqu’à présent, nous remarquons que le message voyage à travers le pipeline, généralement via des courtiers de messages. Cependant, nous pouvons ignorer l’envoi de toutes les données via le pipeline. Une alternative pourrait être de stocker les données à un emplacement temporaire sur un système de fichiers distribué ou dans une base de données préférée. Chaque étape de filtre peut transmettre l’emplacement de stockage des données à partir duquel elles peuvent être lues.
La mise en œuvre réduit les données circulant dans le tube. De plus, le dernier état des données est toujours conservé en cas de défaillance du pipeline. Mais l’inconvénient de l’implémentation est qu’elle augmente les opérations d’E/S, ce qui augmente les risques d’exceptions.
Comportement des messages dynamiques des canaux et des filtres
Comportement du filtre
Le nombre de filtres doit être développé avec soin dans un pipeline. Lors de la conception de filtres, il est judicieux de décomposer un grand filtre en plusieurs étapes constitutives afin de minimiser la complexité. D’autre part, les filtres qui sont légers sur le traitement peuvent être combinés en une seule étape pour réduire la surcharge. Les étapes de filtrage introduites dans un pipeline doivent être suffisamment bonnes pour maximiser la simultanéité, mais suffisamment petites pour minimiser la surcharge de transfert de données via les étapes du pipeline.
Exemple de cas d’utilisation
Les sections précédentes ont clairement expliqué comment utiliser ce modèle. Cette section fournit un exemple pour expliquer l’utilisation des modèles. Disons que nous collectons un flux continu de données pour un projet d’apprentissage automatique. Étant donné que les données sont collectées à partir de plusieurs sources, les données brutes peuvent être dans différents formats, incomplètes ou sales. Les données brutes doivent être nettoyées et structurées avant d’effectuer toute analyse sur celles-ci. Le nettoyage des données est un processus fastidieux et chronophage mais est une étape nécessaire pour obtenir un résultat de qualité. Le processus de nettoyage des données comprend six étapes, à savoir :
- Supprimer les doublons
- Supprimer les données non pertinentes
- Corriger les erreurs structurelles
- Filtrer les valeurs aberrantes indésirables
- Gérer les données manquantes
- Validez vos données
Bien que nous puissions écrire un service qui cache la complexité du nettoyage des données, il aurait les mêmes inconvénients que ceux énumérés précédemment. Il serait utile de créer un pipeline pour le nettoyage des données, car quelques étapes du pipeline ci-dessus peuvent nécessiter un traitement et un matériel spécialisés. De plus, il existe plusieurs outils prêts à l’emploi disponibles qui peuvent être utilisés dans le pipeline.
Résumé
En fin de compte, je dirais que le modèle aide à créer des applications évolutives. Le motif ressemble à un système d’approvisionnement en eau, où un flux d’eau s’écoule à travers le canal via divers filtres. Le nombre de filtres installés sur le canal d’alimentation est basé sur l’utilisation finale de l’eau. Par exemple, l’eau fournie à un ménage passera par plus de filtres que l’eau fournie pour l’irrigation.