Aller au contenu principal

Concept #037

Architecture

Architecture Event-Driven

#0375 min de lecture
  • architecture
  • microservices
  • programmation
Event-Driven : réactivité et résilience

Quand un utilisateur passe une commande sur votre site, que se passe-t-il ensuite ? Envoyer un email de confirmation, mettre à jour le stock, notifier l'équipe logistique, générer une facture... Si tout cela se déroule de manière synchrone, l'utilisateur attend. Si l'un de ces services tombe, toute la chaîne est bloquée. L'architecture Event-Driven résout exactement ce problème.

Le principe : producteur, événement, consommateur

Une architecture Event-Driven repose sur trois acteurs fondamentaux.

Le producteur est le service qui détecte qu'il s'est passé quelque chose de significatif et publie un événement. Il ne sait pas — et ne cherche pas à savoir — qui va traiter cet événement. Son rôle s'arrête là.

L'événement est un message immuable qui décrit un fait accompli. On ne dit pas "fais ceci", on dit "ceci s'est produit". Par convention, un événement se nomme au passé : OrderPlaced, UserRegistered, PaymentFailed. Il embarque toutes les données nécessaires à sa compréhension.

Le consommateur est le service qui s'abonne à certains types d'événements et réagit en conséquence. Plusieurs consommateurs peuvent écouter le même événement simultanément, chacun faisant ce qui le concerne.

Ce modèle s'oppose à l'appel direct entre services, où le service A appelle explicitement le service B. Ici, A et B ne se connaissent pas. C'est le principe du découplage.

Pourquoi adopter l'Event-Driven ?

Le découplage

Dans une architecture classique, les services sont liés les uns aux autres. Modifier le service d'envoi d'emails peut casser le service de commande. Avec l'Event-Driven, chaque service est autonome. On peut ajouter un nouveau consommateur — par exemple un service d'analyse des ventes — sans toucher au code existant. L'évolution du système devient bien plus sûre.

La résilience

Si le service d'envoi d'emails est temporairement indisponible, les événements s'accumulent dans une file d'attente. Quand le service redémarre, il reprend le traitement là où il s'est arrêté. Les autres services n'ont jamais été interrompus. Le système dans son ensemble continue de fonctionner malgré la défaillance d'une de ses parties.

La scalabilité

Les consommateurs peuvent être multipliés indépendamment les uns des autres. Si le traitement des paiements est le goulot d'étranglement, on peut lancer plusieurs instances de ce seul consommateur sans toucher au reste de l'architecture. La montée en charge est ciblée et économique.

La réactivité pour l'utilisateur

Puisque les tâches lourdes sont déléguées en arrière-plan, la réponse à l'utilisateur est immédiate. Il reçoit une confirmation dès que sa commande est enregistrée, sans attendre que l'email soit envoyé ou que le stock soit mis à jour.

Le rôle du broker

Entre les producteurs et les consommateurs se trouve le broker — aussi appelé bus de messages ou message queue. C'est l'intermédiaire qui reçoit les événements, les persiste et les distribue aux consommateurs concernés.

Apache Kafka est la référence pour les systèmes à fort volume. Il stocke les événements de manière durable et ordonnée dans des "topics". Un consommateur peut relire l'historique des événements depuis n'importe quel point dans le temps, ce qui est précieux pour la reconstruction d'état ou le débogage.

RabbitMQ est plus adapté aux cas d'usage où la flexibilité du routage prime. Il propose différents modèles d'échange (direct, fanout, topic) et excelle dans les architectures où les messages doivent être distribués selon des règles complexes.

D'autres solutions comme AWS SQS/SNS, Google Pub/Sub ou Azure Service Bus offrent des alternatives managées qui réduisent la charge opérationnelle.

Exemple concret : la commande e-commerce

Imaginons qu'un client finalise son panier. Le service de commande enregistre la commande et publie un seul événement : OrderPlaced.

Trois consommateurs réagissent en parallèle, indépendamment les uns des autres :

  • Le service email envoie une confirmation au client
  • Le service stock décrémente les quantités disponibles
  • Le service notification alerte l'équipe logistique

Si demain on veut générer une facture PDF automatiquement, il suffit d'ajouter un quatrième consommateur qui écoute OrderPlaced. Zéro modification du service de commande, zéro risque de régression.

Patterns associés

Event Sourcing

Plutôt que de stocker l'état actuel d'une entité, on stocke la liste de tous les événements qui ont conduit à cet état. Le solde d'un compte bancaire n'est pas un chiffre en base de données, c'est le résultat du rejeu de toutes les transactions. Cela offre un audit trail complet et la possibilité de reconstruire l'état à n'importe quel moment passé.

CQRS (Command Query Responsibility Segregation)

Ce pattern sépare les opérations d'écriture (commands) des opérations de lecture (queries). Il se marie naturellement avec l'Event-Driven : les événements alimentent des projections optimisées pour la lecture, tandis que les commandes modifient l'état via les événements. Chaque côté peut être dimensionné indépendamment.

Les défis à anticiper

L'architecture Event-Driven n'est pas sans contreparties.

La cohérence éventuelle est le premier écueil. Entre le moment où un événement est publié et celui où tous les consommateurs l'ont traité, le système est dans un état intermédiaire. Concevoir une interface utilisateur qui gère cet entre-deux demande une réflexion spécifique.

Le débogage devient plus complexe. Retracer le parcours d'une requête à travers plusieurs services découplés nécessite des outils de tracing distribué comme Jaeger ou Zipkin. Sans eux, comprendre pourquoi un email n'a pas été envoyé peut vite devenir un casse-tête.

La gestion de l'ordre des événements peut aussi poser problème. Si OrderCancelled est traité avant OrderPlaced, le comportement du système sera incorrect. Kafka garantit l'ordre au sein d'une partition, mais cela implique une réflexion sur la conception des topics.

Enfin, l'idempotence des consommateurs est indispensable. Un événement peut être livré plus d'une fois en cas d'erreur réseau. Chaque consommateur doit être capable de traiter le même événement plusieurs fois sans produire d'effets indésirables.


L'architecture Event-Driven est un changement de paradigme profond : on passe d'un modèle où les services se commandent mutuellement à un modèle où ils réagissent à ce qui se passe autour d'eux. Cela demande un effort de conception initial plus important, mais le gain en résilience, en scalabilité et en maintenabilité en fait un choix incontournable pour les systèmes distribués à forte charge.