Dans un système requête-réponse, les flèches du diagramme sont le graphe d'appels. Dans un système orienté événements, ce n'est pas le cas. Un producteur écrit un événement dans un topic et ne sait pas qui le lit. Dessinez cela naïvement, chaque service relié à une grande boîte Kafka, et le diagramme cache tout ce dont vous avez besoin : quels événements existent, qui y réagit, dans quel ordre, et ce qui se passe quand un consommateur échoue.
Ce guide vous propose une notation pour les diagrammes d'architecture orientée événements qui garde le flux lisible, déroule un exemple de traitement de commandes sur Kafka et couvre les détails qu'on oublie souvent de dessiner : les clés, les groupes de consommateurs, l'outbox et le chemin dead-letter.
Ce que le diagramme doit montrer
Un diagramme orienté événements doit répondre à ces questions sans document séparé :
- Quels événements existent ? Nommés au passé, comme
OrderPlacedouPaymentFailed. - Qui produit chacun d'eux ? Un seul propriétaire par type d'événement, c'est le choix sain par défaut.
- Qui les consomme, et dans quel groupe de consommateurs ? Dans Kafka, chaque groupe de consommateurs reçoit chaque événement : chaque groupe est donc un lecteur distinct.
- Qu'est-ce qui détermine l'ordre ? Kafka ne garantit l'ordre qu'au sein d'une partition, et c'est la clé qui choisit la partition.
- Que se passe-t-il en cas d'échec ? Les nouvelles tentatives, les dead-letter topics, et qui rejoue les messages.
Une notation qui fonctionne
| Élément | Comment le dessiner |
|---|---|
| Producteur | Un nœud de service relié au topic par un lien en tirets, étiqueté avec le type d'événement |
| Topic | Un nœud à part entière, nommé comme dans le cluster (orders.v1), avec la clé dans l'étiquette |
| Groupe de consommateurs | Un lien en tirets du topic vers le consommateur, étiqueté avec l'identifiant du groupe |
| Événement ou commande | Les événements au passé (OrderPlaced), les commandes à l'impératif (ReserveStock) |
| Dead-letter topic | Un nœud topic distinct, alimenté par le consommateur qui a abandonné |
| Connecteur | Un nœud entre un topic et un stockage externe, comme un sink vers l'entrepôt de données |
| Cluster de brokers | Un cadre autour des topics ; brokers et partitions vont sur le diagramme d'exploitation |
Utilisez des liens en trait plein uniquement pour les appels synchrones, comme une requête HTTP vers un prestataire de paiement. Le lecteur voit alors d'un coup d'œil quelles parties d'un flux se déroulent dans la même requête et lesquelles arrivent plus tard.
L'exemple : événements de commande sur Kafka
Une boutique en ligne traite ses commandes avec des événements :
- Le service orders écrit la commande et une ligne d'outbox dans la même transaction de base de données.
- Un outbox relay (Debezium sur Kafka Connect) lit l'outbox via le journal de la base de données et publie
OrderPlaceddansorders.v1, avecorder_idcomme clé. - Trois groupes de consommateurs lisent
orders.v1: payments débite la carte, inventory réserve le stock et un warehouse sink charge chaque événement dans l'entrepôt de données. - Payments publie
PaymentSucceededouPaymentFaileddanspayments.v1, avecorder_idcomme clé lui aussi, et le service orders le consomme pour mettre à jour le statut de la commande. - Quand inventory ne parvient pas à traiter un message après trois tentatives, il l'écrit dans
inventory.dlqet passe à la suite.
Voici l'ensemble du flux sur un seul canevas :
Contenu du diagramme
- Orders
- Orders DB (orders + outbox)
- Outbox relay
- Kafka cluster
- payments.v1 · key order_id
- orders.v1 · key order_id
- inventory.dlq
- Payments
- Warehouse sink
- Inventory
- Data warehouse
- order + outbox row, one transaction
- reads WAL
- OrderPlaced
- group: payments
- group: warehouse-sink
- group: inventory
- PaymentSucceeded/Failed
- group: orders
- load
- after 3 failed attempts
Remarquez ce que le diagramme rend évident : personne n'appelle payments, ajouter un quatrième groupe de consommateurs ne change rien en amont, et les événements d'une même commande restent dans l'ordre au sein de chaque topic, car les deux topics ont order_id comme clé (Kafka ne garantit aucun ordre entre topics).
Cinq règles pour les diagrammes orientés événements
1. Les topics sont des nœuds, pas des flèches
Une flèche du service orders vers payments étiquetée « Kafka » suggère un appel qui n'existe pas. Dessinez le topic comme un nœud entre les deux. C'est un objet bien réel, avec un nom, un propriétaire, une durée de rétention et un schéma.
2. Les flèches suivent les données
Dessinez du producteur vers le topic, puis du topic vers le consommateur, dans le sens où circulent les données. Les consommateurs Kafka fonctionnent en pull, mais un diagramme dont les flèches vont des consommateurs vers les topics se lit à l'envers pour presque tout le monde. Si la sémantique pull compte pour la discussion, ajoutez une note.
3. Étiquetez les événements et les groupes de consommateurs
Inscrivez le type d'événement sur le lien du producteur et le groupe de consommateurs sur chaque lien de consommateur. Quand quelqu'un demande « qui d'autre lit OrderPlaced ? », la réponse est la liste des liens étiquetés qui partent du topic.
4. Montrez la clé quand l'ordre compte
Kafka garantit l'ordre au sein d'une partition, et les événements de même clé vont dans la même partition. Si vos consommateurs partent du principe qu'ils verront OrderPlaced avant OrderCancelled, écrivez la clé sur le topic : orders.v1 · key order_id. Un topic sans clé dans son étiquette appelle forcément la question.
5. Dessinez les cas d'échec
Les groupes de consommateurs Kafka n'ont pas de dead-letter queue intégrée : c'est votre code consommateur ou votre framework qui décide combien de fois réessayer et où mettre un message qu'il ne peut pas traiter (les connecteurs sink de Kafka Connect, eux, ont bien un paramètre de dead-letter topic). Dessinez cette décision. Un dead-letter topic relié au consommateur, avec une note indiquant qui le surveille et comment les messages sont rejoués, vous évite un incident.
Dessinez l'outbox, pas le raccourci
Si un service écrit dans sa base de données puis publie dans Kafka en deux étapes distinctes, un crash entre les deux fait perdre un événement, ou en fait publier un pour une modification jamais validée. Le pattern outbox évite cette double écriture : le service écrit l'événement dans une table outbox au sein de la même transaction, et un relais le publie.
Sur le diagramme, dessinez le vrai chemin : du service à la base de données, puis au relais, puis au topic. Une flèche directe du service vers le topic décrirait un autre système, moins fiable, et les gens prendront des décisions sur cette base.
Chorégraphie ou orchestration
L'exemple utilise la chorégraphie : les services réagissent aux événements les uns des autres, et personne ne pilote l'ensemble du flux. Si vous utilisez plutôt un orchestrateur, c'est-à-dire un moteur de workflow qui envoie des commandes comme ReserveStock et attend les réponses, dessinez l'orchestrateur comme un service au centre et étiquetez ses liens comme des commandes. Dans les deux cas, numérotez les étapes du flux principal sur les liens pour que les lecteurs puissent suivre la saga dans l'ordre.
Gardez le cluster hors de la vue logique
Brokers, partitions, facteurs de réplication et nœuds contrôleurs comptent pour la capacité et l'exploitation, pas pour comprendre le flux. Mettez-les sur un diagramme d'exploitation séparé. Dans la vue logique, un cadre étiqueté « Kafka cluster » autour des topics suffit.
Construisez-le dans Archboard
- Connectez-vous avec Google ou GitHub et créez un diagramme.
- Ajoutez les services comme nœuds Conteneur du pack Modèle C4, et la base de données orders depuis le pack Données (Postgres).
- Ajoutez un Cadre du pack Base étiqueté
Kafka clusteret placez-y des nœuds Sujet du pack Données. - Ajoutez l'outbox relay et le warehouse sink comme conteneurs, avec
Kafka Connectdans le champ Technologie, ainsi qu'un nœud Entrepôt de données du pack Données. - Connectez les ports, passez les liens d'événements en tirets et étiquetez-les avec les types d'événements et les groupes de consommateurs.
- Ouvrez le diagramme en mode présentation pour la revue, partagez le lien en direct ou exportez-le en SVG et PNG.
L'exemple utilise 11 nœuds de diagramme, dans la limite des 15 du plan Free. Pour une autre mise en page de streaming, consultez /examples/streaming-data-platform, et pour le côté synchrone d'une boutique similaire, le guide du diagramme d'architecture microservices.
FAQ
Faut-il dessiner les partitions ? Pas dans la vue logique. Indiquez le nombre de partitions dans l'étiquette du topic si c'est important, et dessinez partitions et brokers sur un diagramme d'exploitation.
Sur le diagramme, en quoi une file d'attente diffère-t-elle d'un topic ? Dans une file d'attente, chaque message va à un seul consommateur ; dans un topic Kafka, chaque groupe de consommateurs reçoit chaque message. Utilisez un nœud File d'attente pour les files comme SQS ou RabbitMQ, et précisez sur quelle sémantique vous vous appuyez.
Où placer les schémas d'événements ? Dans une note ou dans l'étiquette du topic, avec un lien vers le registre de schémas ou le dépôt propriétaire du schéma. Le diagramme doit montrer qu'un contrat existe et où il se trouve.
Comment montrer le rejeu ?
Écrivez la rétention sur le topic (par exemple retention 7d) et ajoutez une note sur la façon dont un groupe de consommateurs réinitialise ses offsets. Le rejeu est une fonctionnalité de conception : rendez-le visible.
Faut-il un diagramme par événement ? Non. Un diagramme par flux métier fonctionne bien. Listez les événements sur les liens et tenez un catalogue d'événements pour la liste complète.