Style d’architecture basée sur les événements
Une architecture pilotée par les événements se compose de producteurs d’événements qui génèrent un flux d’événements, des consommateurs d’événements qui écoutent ces événements et des canaux d’événements qui transfèrent des événements des producteurs aux consommateurs.
Les événements étant remis en quasi-temps réel, les consommateurs peuvent y répondre immédiatement à mesure qu’ils se produisent. Les producteurs sont dissociés des consommateurs : un producteur ne sait pas quels consommateurs écoutent. Les consommateurs sont aussi dissociés les uns des autres, et chaque consommateur voit tous les événements. Ce processus diffère d’un modèle consommateurs concurrents où les consommateurs extrayent les messages d’une file d’attente et qu’un message n’est traité qu’une seule fois, en supposant qu’il n’y a pas d’erreur. Dans certains systèmes, tels qu’Azure Internet of Things (IoT), les événements doivent être ingérés à des volumes élevés.
Une architecture pilotée par les événements peut utiliser un modèle de publication-abonnement ou un modèle de flux d’événements.
Pub/sub : L’infrastructure de messagerie de publication-abonnement effectue le suivi des abonnements. Quand un événement est publié, elle communique l’événement à chaque abonné. Un événement ne peut pas être relecté après sa réception et les nouveaux abonnés ne voient pas l’événement.
Diffusion en continu d’événements : Les événements sont écrits dans un journal. Les événements sont strictement ordonnés dans une partition et sont durables. Les clients ne s’abonnent pas au flux. Au lieu de cela, un client peut lire n’importe quelle partie du flux. Le client est responsable de l’avancement de sa position dans le flux. Cela signifie qu’un client peut rejoindre à tout moment et relire des événements.
Du côté du consommateur, il existe quelques variantes courantes :
Traitement d’événements simple : Un événement déclenche immédiatement une action dans le consommateur. Par exemple, vous pouvez utiliser Azure Functions avec un déclencheur Azure Service Bus afin qu’une fonction s’exécute chaque fois qu’un message est publié dans une rubrique Service Bus.
Corrélation d’événements de base : Un consommateur traite quelques événements métier discrets, les met en corrélation par un identificateur et conserve les informations des événements antérieurs à utiliser lors du traitement des événements ultérieurs. Les bibliothèques telles que NServiceBus et MassTransit prennent en charge ce modèle.
Traitement des événements complexes : Un consommateur utilise une technologie comme Azure Stream Analytics pour analyser une série d’événements et identifier des modèles dans les données d’événement. Par exemple, vous pouvez agréger des lectures à partir d’un appareil incorporé sur une fenêtre de temps et générer une notification si la moyenne mobile dépasse un certain seuil.
Traitement des flux d’événements : Utilisez une plateforme de streaming de données, telle qu’Azure IoT Hub ou Apache Kafka, en tant que pipeline pour ingérer des événements et les alimenter vers des processeurs de flux. Les processeurs de flux agissent de façon à traiter ou transformer le flux. Il peut y avoir plusieurs processeurs de flux pour différents sous-systèmes de l’application. Cette approche est parfaitement adaptée aux charges de travail IoT.
La source des événements peut être externe au système, comme les appareils physiques dans une solution IoT. Dans ce cas, le système doit pouvoir ingérer les données au niveau du volume et du débit requis par la source de données.
Il existe deux approches principales pour structurer les charges utiles d’événement. Lorsque vous contrôlez vos consommateurs d’événements, vous pouvez décider de la structure de charge utile pour chaque consommateur. Cette stratégie vous permet de combiner des approches selon les besoins au sein d’une seule charge de travail.
Incluez tous les attributs requis dans la charge utile : Utilisez cette approche lorsque vous souhaitez que les consommateurs disposent de toutes les informations disponibles sans avoir à interroger une source de données externe. Toutefois, cela peut entraîner des problèmes de cohérence des données en raison de plusieurs systèmes d’enregistrement, en particulier après les mises à jour. La gestion des contrats et le contrôle de version peuvent également devenir complexes.
Incluez uniquement des clés dans la charge utile : Dans cette approche, les consommateurs récupèrent les attributs nécessaires, tels qu’une clé primaire, pour extraire indépendamment les données restantes d’une source de données. Cette méthode offre une meilleure cohérence des données, car elle possède un seul système d’enregistrement. Toutefois, elle peut s’effectuer moins bien que la première approche, car les consommateurs doivent interroger fréquemment la source de données. Vous avez moins de préoccupations concernant le couplage, la bande passante, la gestion des contrats ou le contrôle de version, car les événements plus petits et les contrats plus simples réduisent la complexité.
Dans le diagramme précédent, chaque type de consommateur s’affiche sous la forme d’une seule zone. Pour éviter que le consommateur devienne un point de défaillance unique dans le système, il est courant d’avoir plusieurs instances d’un consommateur. Plusieurs instances peuvent également être nécessaires pour gérer le volume et la fréquence des événements. Un seul consommateur peut traiter des événements sur plusieurs threads. Cette configuration peut créer des défis si les événements doivent être traités dans l’ordre ou nécessitent une sémantique exactement une fois. Pour plus d’informations, consultez Réduire la coordination.
Il existe deux topologies principales dans de nombreuses architectures pilotées par les événements :
Topologie broker : Les composants diffusent des occurrences en tant qu’événements sur l’ensemble du système. Les autres composants agissent sur l’événement ou ignorent l’événement. Cette topologie est utile lorsque le flux de traitement des événements est relativement simple. Il n’y a pas de coordination ou d’orchestration centrale, donc cette topologie peut être dynamique. Elle est fortement découplée, ce qui contribue à l'évolutivité, à la réactivité et à la tolérance aux pannes des composants. Aucun composant ne possède ou ne connaît l’état d’une transaction commerciale à plusieurs étapes, et les actions sont effectuées de manière asynchrone. Par la suite, les transactions distribuées sont risquées, car il n’existe aucun moyen natif de redémarrer ou de relecture. Vous devez examiner attentivement la gestion des erreurs et les stratégies d’intervention manuelle, car cette topologie peut être une source d’incohérence des données.
Topologie du médiateur : Cette topologie traite certaines des lacunes de la topologie broker. Il existe un médiateur d’événements qui gère et contrôle le flux des événements. Le médiateur d'événements maintient l'état et gère le traitement des erreurs et les capacités de redémarrage. Contrairement à la topologie broker, dans cette topologie, les composants diffusent des occurrences sous forme de commandes et uniquement pour les canaux désignés. Ces canaux sont généralement des files d’attente de messages. Les consommateurs sont censés traiter ces commandes. Cette topologie offre un meilleur contrôle, une meilleure gestion des erreurs distribuées et une meilleure cohérence des données. Cette topologie introduit un couplage accru entre les composants, et le médiateur de l’événement peut devenir un goulot d’étranglement ou une préoccupation de fiabilité.
Quand utiliser cette architecture
Vous devez utiliser cette architecture quand :
- Plusieurs sous-systèmes doivent traiter les mêmes événements.
- Le traitement en temps réel avec un décalage de temps minimal est nécessaire.
- Le traitement d’événements complexe, tel que la mise en correspondance de modèles ou l’agrégation au fil des fenêtres de temps, est requis.
- Un volume élevé et une vitesse élevée de données sont nécessaires, comme avec, par exemple, IoT.
Avantages
Les avantages de cette architecture sont les suivants :
- Les producteurs et les consommateurs sont dissociés.
- Aucune intégration point à point. Simplicité d’ajout de nouveaux consommateurs au système.
- Les consommateurs peuvent répondre aux événements immédiatement lorsqu’ils se produisent.
- Hautement évolutif, élastique et distribué.
- Les sous-systèmes ont des vues indépendantes du flux d’événements.
Défis
Transmission non garantie.
Dans certains systèmes, surtout dans les scénarios IoT, il est essentiel de garantir la transmission des événements.
Traitement des événements dans l’ordre ou une seule fois.
Pour la résilience et la scalabilité, chaque type de consommateur s’exécute généralement dans plusieurs instances. Ce processus peut créer un défi si les événements doivent être traités dans l’ordre dans un type consommateur, ou si la logique de traitement des messages idempotent n’est pas implémentée.
Coordination des messages entre les services.
Les processus métier ont souvent plusieurs services qui publient et s’abonnent aux messages pour obtenir un résultat cohérent dans toute une charge de travail. Vous pouvez utiliser des modèles de flux de travail tels que le modèle chorégraphique et l’orchestration Saga pour gérer de manière fiable les flux de messages entre différents services.
Gestion des erreurs.
L’architecture pilotée par les événements utilise principalement la communication asynchrone. Un défi avec la communication asynchrone est la gestion des erreurs. Une façon de résoudre ce problème consiste à utiliser un processeur de gestionnaire d’erreurs distinct. Lorsque le consommateur d’événements rencontre une erreur, il envoie immédiatement et de manière asynchrone l’événement erroné au processeur du gestionnaire d’erreurs et se déplace. Le processeur de gestion des erreurs tente de corriger l’erreur et renvoie l’événement au canal d’ingestion d’origine. Toutefois, si le processeur du gestionnaire d’erreurs échoue, il peut envoyer l’événement erroné à un administrateur pour une inspection plus approfondie. Si vous utilisez un processeur de gestionnaire d’erreurs, les événements erronés sont traités hors séquence lorsqu’ils sont soumis.
Perte de données.
Un autre défi avec la communication asynchrone est la perte de données. Si l’un des composants se bloque avant de traiter et de remettre l’événement à son composant suivant, l’événement est supprimé et ne le rend jamais dans la destination finale. Pour réduire le risque de perte de données, conservez les événements en transit et supprimez ou supprimez les événements uniquement lorsque le composant suivant accuse réception de l’événement. Ces fonctionnalités sont appelées mode accusé de réception du client et support du dernier participant.
Implémentation d’un modèle de demande-réponse traditionnel.
Parfois, le producteur d’événements nécessite une réponse immédiate du consommateur d’événements, par exemple obtenir l’éligibilité du client avant de passer une commande. Dans une architecture pilotée par les événements, la communication synchrone peut être obtenue à l’aide de la messagerie de demande-réponse.
Ce modèle est généralement implémenté avec deux files d’attente : une file d’attente de requêtes et une file d’attente de réponse. Le producteur d’événements envoie une requête asynchrone à une file d’attente de requêtes, interrompt d’autres opérations sur cette tâche et attend une réponse dans la file d’attente de réponse. Cette approche transforme efficacement ce modèle en processus synchrone. Les consommateurs d’événements traitent ensuite la demande et envoient la réponse par le biais d’une file d’attente de réponse. Cette approche utilise généralement un ID de session pour le suivi, afin que le producteur d’événements sache quel message dans la file d’attente de réponse est lié à la requête spécifique. La demande d’origine peut également spécifier le nom de la file d’attente de réponse, potentiellement éphémère, dans un en-tête de réponse ou un autre attribut personnalisé mutuellement convenu.
Maintenance du nombre approprié d’événements.
La génération d’un nombre excessif d’événements affinés peut saturer et submerger le système, ce qui rend difficile l’analyse efficace du flux global des événements. Ce problème est aggravé lorsque les modifications doivent être restaurées. À l’inverse, la consolidation excessive des événements peut également créer des problèmes, ce qui entraîne un traitement et des réponses inutiles des consommateurs d’événements.
Pour obtenir le bon équilibre, tenez compte des conséquences des événements et indiquez si les consommateurs doivent inspecter les charges utiles des événements pour déterminer leurs réponses. Par exemple, si vous disposez d’un composant de vérification de conformité, il peut suffire de publier seulement deux types d’événements : conformes et nonconformes. Cette approche permet de s’assurer que seuls les consommateurs pertinents traitent chaque événement, ce qui empêche le traitement inutile.
Autres considérations
La quantité de données à inclure dans un événement peut être un facteur important qui affecte les performances et les coûts. Vous pouvez simplifier le code de traitement et éliminer les recherches supplémentaires en plaçant toutes les informations pertinentes nécessaires au traitement directement dans l’événement. Lorsque vous ajoutez uniquement une quantité minimale d’informations à un événement, comme quelques identificateurs, vous réduisez le temps de transport et le coût. Toutefois, cette approche nécessite que le code de traitement récupère toutes les informations supplémentaires dont elle a besoin. Pour plus d’informations, consultez Mettre vos événements sur un régime alimentaire.
Une requête n’est visible que par le composant de gestion des demandes. Toutefois, les événements sont souvent visibles par plusieurs composants d’une charge de travail, même si ces composants ne sont pas destinés à les consommer. Pour travailler avec une mentalité de « violation de principe », gardez à l’esprit les informations que vous incluez dans les événements afin d’empêcher l’exposition involontaire d’informations.
De nombreuses applications utilisent l’architecture basée sur les événements comme architecture principale. Vous pouvez combiner cette approche avec d’autres styles architecturaux pour créer une architecture hybride. Les combinaisons classiques incluent les microservices et les canaux et les filtres. Intégrez l’architecture pilotée par les événements pour améliorer les performances du système en éliminant les goulots d’étranglement et en fournissant une pression arrière pendant les volumes de requêtes élevés.
Les domaines spécifiques couvrent souvent plusieurs producteurs d’événements, consommateurs ou canaux d’événements. Les modifications apportées à un domaine particulier peuvent affecter de nombreux composants.
Ressources associées
- Vidéo de discussion de la communauté sur les considérations relatives au choix entre la chorégraphie et l’orchestration.