Event-Driven Architecture
Comment concevoir des systèmes réactifs où les composants communiquent au moyen d'événements, en obtenant découplage, scalabilité et traitement asynchrone.
Quel problème résout-il
Dans une architecture traditionnelle fondée sur des appels synchrones (request-response), les services sont fortement couplés : l’émetteur doit connaître le récepteur, attendre sa réponse et gérer ses défaillances. Cela engendre plusieurs problèmes :
- Couplage temporel : L’émetteur est bloqué jusqu’à ce que le récepteur réponde
- Couplage de connaissance : L’émetteur doit savoir qui traite sa requête
- Scalabilité limitée : Ajouter un nouveau consommateur exige de modifier l’émetteur
- Fragilité : Si le récepteur est hors service, l’émetteur échoue également
Communication synchrone (couplée):
Order Service ──► Inventory Service (espera respuesta)
──► Payment Service (espera respuesta)
──► Notification Service (espera respuesta)
──► Analytics Service (espera respuesta)
Order Service conoce a TODOS los servicios
Si uno falla, el pedido falla
Agregar un servicio = modificar Order Service
Comment ça fonctionne
L’architecture orientée événements (EDA) inverse le modèle de communication. Plutôt qu’un service appelle directement les autres, il publie un événement qui décrit quelque chose qui s’est produit. Les services intéressés s’abonnent à ces événements et réagissent de manière indépendante.
Communication par événements (découplée):
Order Service ──evento──► Event Bus
"OrderCreated"
│
┌───────────┼───────────┐
▼ ▼ ▼
Inventory Payment Notification
Service Service Service
Order Service NO conoce a los consumidores
Cada servicio reacciona de forma independiente
Agregar un servicio = suscribirse al evento
Concepts clés
| Concept | Description | Exemple |
|---|---|---|
| Événement | Enregistrement immuable de quelque chose qui s’est produit | OrderCreated, PaymentProcessed |
| Producteur | Service qui publie des événements | Order Service publie OrderCreated |
| Consommateur | Service qui réagit aux événements | Inventory Service écoute OrderCreated |
| Event Bus/Broker | Infrastructure qui transporte les événements | Kafka, RabbitMQ, Amazon SNS/SQS |
| Topic/Queue | Canal par lequel circulent les événements | orders.created, payments.processed |
Types d’événements
Domain Events (événements de domaine) : Ils représentent des faits métier.
{
"type": "OrderCreated",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"orderId": "ORD-001",
"customerId": "USR-123",
"items": [{"productId": "P001", "quantity": 2}],
"total": 150.00
}
}
Integration Events (événements d’intégration) : Ils communiquent les changements entre bounded contexts.
{
"type": "InventoryReserved",
"source": "inventory-service",
"data": {
"orderId": "ORD-001",
"reservationId": "RES-456",
"status": "confirmed"
}
}
Modèles de livraison
Pub/Sub (Publish-Subscribe) : Un événement est livré à tous les abonnés.
Productor ──► Topic ──► Consumidor A
──► Consumidor B
──► Consumidor C
Event Streaming : Les événements sont stockés dans un log persistant et les consommateurs les lisent à leur propre rythme.
Productor ──► Log persistente (Kafka)
[evento1, evento2, evento3, ...]
Consumidor A: leyendo evento 3 (al día)
Consumidor B: leyendo evento 1 (atrasado, procesando)
Consumidor C: nuevo, empieza desde evento 1
Garanties de livraison
| Garantie | Description | Usage |
|---|---|---|
| At-most-once | L’événement est livré au maximum une fois (il peut être perdu) | Métriques, analytics |
| At-least-once | L’événement est livré au moins une fois (il peut être dupliqué) | La plupart des cas (avec idempotence) |
| Exactly-once | L’événement est livré exactement une fois | Transactions financières (difficile à obtenir) |
Avantages
- Découplage : Producteurs et consommateurs ne se connaissent pas entre eux
- Scalabilité : Ajouter des consommateurs n’exige pas de modifier les producteurs
- Résilience : Si un consommateur est hors service, les événements s’accumulent et sont traités à son retour
- Traitement asynchrone : Le producteur n’attend pas que les consommateurs aient terminé
- Audit naturel : Les événements forment un log de tout ce qui s’est produit dans le système
- Extensibilité : De nouvelles fonctionnalités s’ajoutent en s’abonnant aux événements existants
Trade-offs / Inconvénients
- Cohérence à terme : Les données ne sont pas mises à jour instantanément dans tous les services
- Complexité du débogage : Retracer le flux d’un événement à travers de multiples services est difficile
- Ordonnancement : Garantir l’ordre de traitement des événements exige une conception soigneuse
- Doublons : Les consommateurs doivent être idempotents pour gérer les événements dupliqués
- Infrastructure supplémentaire : Vous avez besoin d’un broker de messagerie (Kafka, RabbitMQ) et de son exploitation
- Tests complexes : Tester des flux asynchrones est plus difficile que tester des appels synchrones
Quand l’utiliser
- Systèmes où plusieurs services doivent réagir au même événement
- Lorsque le traitement peut être asynchrone (vous n’avez pas besoin d’une réponse immédiate)
- Systèmes avec des exigences élevées de scalabilité et de throughput
- Lorsque vous devez découpler des services pour qu’ils évoluent de manière indépendante
- Flux métier complexes comportant plusieurs étapes (commandes, paiements, expéditions)
- Lorsque vous avez besoin d’un log d’audit de tout ce qui se passe dans le système
Quand l’éviter
- Opérations qui exigent une réponse synchrone immédiate (requêtes d’utilisateur)
- Systèmes simples avec peu de services et des flux linéaires
- Lorsque la cohérence forte est une exigence non négociable
- Équipes sans expérience des systèmes distribués et du débogage asynchrone
- Lorsque vous ne pouvez pas justifier l’infrastructure d’un broker de messagerie
Technologies et implémentations courantes
| Catégorie | Options |
|---|---|
| Event Streaming | Apache Kafka, Amazon Kinesis, Azure Event Hubs |
| Message Brokers | RabbitMQ, Amazon SQS/SNS, Google Pub/Sub, NATS |
| Event Store | EventStoreDB, Kafka (comme event store) |
| Frameworks | Spring Cloud Stream, MassTransit (.NET), Axon Framework |
| Observabilité | OpenTelemetry, Jaeger, Zipkin (tracing distribué) |
Relation avec d’autres patterns
- Saga Pattern : Utilise des événements pour coordonner les transactions distribuées entre services
- Outbox Pattern : Garantit la publication fiable des événements en même temps que les changements dans la base de données
- CQRS : Sépare les lectures et les écritures en utilisant des événements pour synchroniser les modèles
- Idempotence : Les consommateurs doivent être idempotents pour gérer les événements dupliqués
- Circuit Breaker : Protège les consommateurs de la surcharge lors des pics d’événements
Prochaines étapes
L’architecture orientée événements est le fondement de la communication dans les microservices modernes. Pour protéger l’intégration avec des systèmes externes qui ne parlent pas votre langage d’événements, explorez l’Anti-Corruption Layer. Pour garantir que les consommateurs gèrent correctement les doublons, consultez le pattern d’Idempotence.