Apache Kafka est souvent introduit comme un « message broker amélioré ». C’est une réduction excessive. Sa persistance des événements, sa scalabilité horizontale et la possibilité de rejouer les messages en font une brique d’architecture à part entière.
Pattern 1 : Event Sourcing
Au lieu de stocker l’état courant d’une entité, vous stockez la séquence des événements qui ont conduit à cet état. Kafka est le log d’événements naturel.
Topic: order-events
├── OrderCreated { id: 123, amount: 450 }
├── OrderPaid { id: 123, method: "card" }
├── OrderShipped { id: 123, tracking: "XK9..." }
└── OrderDelivered { id: 123 }
L’état courant d’une commande est la projection de tous ces événements. Vous pouvez reconstruire l’état à n’importe quel point dans le temps en rejouant depuis le début.
Pattern 2 : CQRS avec Kafka Streams
Command Query Responsibility Segregation sépare les opérations d’écriture (commands) des opérations de lecture (queries). Kafka Streams permet de maintenir des vues matérialisées (read models) à jour en temps réel.
KStream<String, Order> orders = builder.stream("order-events");
KTable<String, OrderSummary> summaryTable = orders
.filter((k, v) -> v.getType().equals("OrderPaid"))
.groupByKey()
.aggregate(OrderSummary::new, (k, v, agg) -> agg.update(v),
Materialized.as("order-summaries"));
Pattern 3 : Saga orchestrée pour les transactions distribuées
Dans un système microservices, une transaction qui implique plusieurs services est un casse-tête. Le pattern Saga décompose la transaction en étapes locales compensables.
1. OrderService → publie OrderCreated
2. PaymentService → consomme OrderCreated, publie PaymentProcessed (ou PaymentFailed)
3. InventoryService→ consomme PaymentProcessed, publie InventoryReserved (ou OutOfStock)
4. ShippingService → consomme InventoryReserved, publie OrderShipped
Si une étape échoue, des événements de compensation sont publiés pour annuler les étapes précédentes.
Pattern 4 : Outbox Pattern pour la cohérence
Le problème : vous mettez à jour votre base de données ET publiez un événement Kafka. Que se passe-t-il si la DB est commitée mais Kafka non, ou l’inverse ?
La solution : l’outbox pattern. Vous écrivez l’événement dans une table outbox de votre base dans la même transaction que votre mise à jour. Un processus séparé lit l’outbox et publie dans Kafka.
| Avantage | Explication |
|---|---|
| Atomicité | DB et événement dans une seule transaction |
| At-least-once | L’outbox est rejoué en cas d’échec |
| Ordre garanti | Les événements sont publiés dans l’ordre d’insertion |
Pattern 5 : Consumer Group pour le scaling
Les consumer groups permettent de distribuer la charge de traitement sur plusieurs instances. Chaque partition est consommée par exactement un consumer du groupe.
consumer = KafkaConsumer(
'order-events',
group_id='payment-processor', # Même group_id = partage des partitions
bootstrap_servers=['kafka:9092']
)
Règle : le nombre de consumers dans un groupe ne peut pas dépasser le nombre de partitions. Planifiez votre nombre de partitions en conséquence.
Notre formation Apache Kafka couvre ces patterns avec des implémentations pratiques.