3.12

Voir en anglais

3.12 Architecture pilotée par les événements et messagerie

Vue d’ensemble et motivation

L’architecture pilotée par les événements (EDA) est un style dans lequel les composants communiquent en produisant et en réagissant à des événements plutôt qu’en s’appelant directement. Un événement est un fait : quelque chose qui s’est déjà produit, tel que « CommandePassée » ou « PaiementCapturé ». Un producteur annonce le fait et continue, et n’importe quel nombre de consommateurs réagit selon son propre calendrier sans que le producteur ne sache qui écoute. C’est une posture différente des appels requête-et-réponse du chapitre 2.3, où un appelant demande à un service spécifique de faire quelque chose et attend la réponse.

Pour une grande organisation, l’attrait est le découplage à l’échelle. Quand vous avez des dizaines d’équipes et des centaines de services, câbler tout ensemble avec des appels point-à-point directs produit une toile fragile où le changement d’une équipe casse celui d’une autre et où personne ne peut tracer pourquoi. Les événements permettent aux équipes de s’intégrer à travers un flux partagé de faits plutôt qu’à travers les internes des unes des autres, et un nouveau consommateur se joint en s’abonnant, sans que le producteur ne change une ligne de code. Cette propriété, plus que le débit brut, est pourquoi les approches pilotées par les événements continuent de se répandre à travers les entreprises remplaçant des intégrations emmêlées et les gouvernements joignant des agences qui possèdent chacune leurs propres systèmes.

Le secteur public obtient un second bénéfice facile à sous-évaluer : un enregistrement durable et ordonné de ce qui s’est passé est un actif d’audit et de transparence. Quand un citoyen demande pourquoi une décision de prestation est sortie ainsi, un journal immuable des événements qui y ont mené répond directement. Mais la conception pilotée par les événements n’est pas gratuite et pas toujours juste : les flux asynchrones sont plus difficiles à tracer, plus difficiles à raisonner, et faciles à surappliquer. Ce chapitre a un avis tranché sur quand le découplage et l’échelle paient pour la complexité ajoutée, et quand un simple appel synchrone vous aurait mieux servi. Il s’appuie sur les réalités des systèmes distribués du chapitre 3.3, donc lisez-le d’abord si vous ne l’avez pas fait.

Principes clés

  • Les événements sont des faits, pas des instructions. Un événement dit ce qui s’est passé ; une commande demande que quelque chose se passe. Gardez-les distincts, et nommez les événements au passé.
  • Le découplage est le but. Les producteurs ne devraient pas savoir ou se soucier de qui consomme leurs événements. S’ils le font, vous avez du couplage portant un costume de messagerie.
  • Concevez pour la livraison au-moins-une-fois. La livraison exactement une fois est un mythe. Rendez chaque consommateur idempotent pour que les doublons soient inoffensifs.
  • L’ordre est une garantie que vous payez. Vous obtenez l’ordonnancement à l’intérieur d’une partition, pas à travers un topic. Choisissez les clés de partition délibérément.
  • Le schéma est le contrat. La forme d’un événement est une interface publique ; faites-la évoluer avec le soin que vous accorderiez à une API publiée.
  • Asynchrone ne signifie pas inobservable. Si vous ne pouvez pas suivre un message de bout en bout, vous ne pouvez pas exploiter le système.
  • La complexité doit être méritée. Le sourcing d’événements, CQRS, et les sagas sont puissants et coûteux ; recourez-y quand le problème l’exige, pas par défaut.

Recommandations

Distinguer événements, commandes, et messages avant de rien construire

Ces trois mots sont utilisés de façon interchangeable, et la confusion cause de vraies erreurs de conception. Une commande est une requête de faire quelque chose (« CapturerPaiement »), dirigée vers un gestionnaire, et elle peut être rejetée. Un événement est une notification que quelque chose s’est déjà passé (« PaiementCapturé »), diffusée à quiconque intéressé, et elle ne peut pas être rejetée parce que le fait est déjà vrai. Un message est l’enveloppe neutre qui porte l’un ou l’autre sur le fil. La distinction façonne le couplage : les commandes couplent l’expéditeur à un récepteur et un résultat spécifiques, tandis que les événements abandonnent le contrôle sur ce qui se passe ensuite. Nommez vos événements au passé, et quand vous vous surprenez à publier un « événement » qui signifie vraiment « veuillez faire cette chose spécifique », vous avez écrit une commande déguisée.

Choisir délibérément les files, les journaux, et le publier/s’abonner

Toute messagerie n’a pas la même forme, et choisir la mauvaise est une erreur précoce courante. Une file de messages livre chaque message à un consommateur et le retire typiquement une fois traité, ce qui convient à la distribution de travail : de nombreux travailleurs tirant des tâches, chacune faite une fois. Un journal d’événements durable (un flux) garde les événements en ordre et laisse de nombreux consommateurs indépendants lire à leur propre rythme, rejouant l’historique depuis n’importe quel point, ce qui convient à la distribution d’événements et à l’audit. Le publier/s’abonner fait publier les producteurs sur un topic et chaque abonné obtient sa propre copie. La règle pratique : si le message est une tâche qu’un travailleur devrait terminer, recourez à une file ; si c’est un fait dont de nombreuses parties peuvent se soucier maintenant ou plus tard, recourez à un journal durable, qui vous donne aussi la relecture pour la récupération et l’intégration de nouveaux consommateurs. Voir le chapitre 3.4 pour comment ces choix interagissent avec votre stratégie de stockage de données.

Préférer la chorégraphie pour l’autonomie, l’orchestration pour le contrôle

Quand un processus métier s’étend sur plusieurs services, vous le coordonnez de l’une de deux façons. Dans la chorégraphie, chaque service réagit aux événements et émet les siens, sans cerveau central : maximalement découplé et bon pour l’autonomie d’équipe, mais le processus global n’existe que comme comportement émergent que nul endroit unique ne décrit. Dans l’orchestration, un coordinateur central pilote les étapes et connaît tout le flux : plus facile à surveiller et modifier, au prix d’un composant dont chaque étape dépend. Une bonne valeur par défaut est la chorégraphie pour des réactions faiblement liées (« quand une commande est expédiée, le service de fidélité attribue des points ») et l’orchestration pour une transaction définie avec une condition de succès claire et un besoin de rapporter le statut. Ne laissez pas un processus important vivre seulement comme un savoir tribal dispersé à travers dix gestionnaires d’événements.

Recourir au sourcing d’événements et à CQRS seulement quand ils méritent leur place

Le sourcing d’événements stocke l’état comme une séquence en ajout seul d’événements plutôt qu’un instantané actuel que vous écrasez, et vous reconstruisez l’état actuel en les rejouant. L’avantage est une piste d’audit parfaite, la capacité de reconstruire tout état passé, et des requêtes temporelles ; le coût est que vous versionnez les schémas d’événement pour toujours, gérez la relecture et les instantanés, et portez un modèle mental que la plupart des développeurs n’ont jamais utilisé. CQRS (Command Query Responsibility Segregation) sépare le modèle d’écriture d’un ou plusieurs modèles de lecture pour que les lectures et écritures s’échelonnent et évoluent indépendamment ; cela s’associe naturellement au sourcing d’événements mais ne l’exige pas. Les deux brillent pour des domaines avec de vrais besoins d’audit, de conformité, ou de requête complexe, ce qui explique pourquoi la finance régulée et l’administration publique les trouvent dignes du dérangement. Pour un simple service créer-lire-mettre-à-jour-supprimer, ils sont de la complexité accidentelle que vous regretterez, donc appliquez-les à la tranche de votre domaine qui en a besoin, pas au système entier par réflexe.

Gérer les transactions distribuées avec des sagas, pas la validation en deux phases

Vous ne pouvez généralement pas envelopper une seule transaction atomique autour de plusieurs services et bases de données. La validation en deux phases distribuée tient des verrous à travers le réseau, réduit la disponibilité, et s’échelonne mal, donc elle convient rarement à un système piloté par les événements. Le motif saga la remplace : modélisez la transaction comme une séquence de transactions locales, chacune émettant un événement qui déclenche la suivante, et donnez à chaque étape une action compensatoire qui l’annule si une étape ultérieure échoue. Si « réserver l’inventaire » réussit mais « débiter la carte » échoue, une compensation libère l’inventaire. Les sagas peuvent être chorégraphiées ou orchestrées, et l’orchestration gagne généralement pour tout ce que vous devez surveiller. Parce que les sagas embrassent la cohérence éventuelle, le système passe par des états intermédiaires (« réservé mais non payé ») avant de converger, donc concevez votre expérience utilisateur et votre piste d’audit pour montrer honnêtement les états « en cours » et « compensé ». Le chapitre 3.3 couvre le même terrain depuis l’angle des systèmes distribués.

Concevoir pour la livraison au-moins-une-fois et rendre les consommateurs idempotents

Les systèmes de message ne peuvent pas vraiment livrer exactement une fois à travers les pannes, parce que l’accusé de réception qui dit « j’ai traité ceci » peut lui-même être perdu, forçant une relivraison. Ce que vous pouvez atteindre est la livraison au-moins-une-fois avec un traitement idempotent, ce qui produit des effets exactement une fois. L’idempotence signifie que traiter le même événement deux fois laisse le même résultat que le traiter une fois ; atteignez cela avec une clé d’idempotence sur chaque événement et un enregistrement de ce que vous avez déjà géré, pour qu’un doublon soit reconnu et abandonné. La livraison au-plus-une-fois (tirer et oublier, pas de relivraison) est plus simple mais perd silencieusement des messages, donc réservez-la aux données que vous pouvez vous permettre de perdre. Traitez l’étiquette « exactement une fois » que certains fournisseurs font la publicité avec suspicion : cela signifie généralement exactement une fois à l’intérieur de la frontière d’un système sous des conditions spécifiques, pas la garantie de bout en bout que la phrase implique.

Contrôler l’ordonnancement avec des partitions, et connaître vos groupes de consommateurs

L’ordonnancement n’est pas global et gratuit ; il est local et payé. Un flux est divisé en partitions, et vous obtenez l’ordonnancement à l’intérieur d’une partition, pas à travers le topic. Les événements sont routés vers une partition par une clé de partition, donc choisir cette clé est comment vous contrôlez ce qui reste ordonné : clé par ID client et les événements d’un client restent en ordre les uns par rapport aux autres, tandis que différents clients se traitent en parallèle. Les groupes de consommateurs laissent un ensemble de travailleurs partager les partitions d’un topic, chaque partition gérée par un travailleur, ce qui est comment vous échelonnez le débit tout en préservant l’ordre par partition ; c’est là où l’évolutivité rencontre la correction, se rattachant au chapitre 3.5. Choisissez une clé de partition qui reflète votre vraie exigence d’ordonnancement et répartit la charge uniformément, parce qu’une clé qui canalise la plupart du trafic dans une seule partition crée un point chaud qu’aucun nombre de travailleurs ne peut soulager.

Traiter les schémas comme des contrats avec un registre et des règles d’évolution

La structure d’un événement est une interface publiée consommée par des équipes que vous ne rencontrerez peut-être jamais, donc la changer négligemment les casse à distance. Placez vos schémas d’événement dans un registre de schéma, un catalogue partagé qui stocke chaque schéma et impose des règles de compatibilité quand un producteur essaie d’en changer un. Adoptez une politique explicite : les changements rétrocompatibles (ajouter un champ optionnel) sont autorisés ; les changements cassants (retirer un champ, changer un type, renommer) exigent une nouvelle version de schéma et un plan de migration. Cela permet aux producteurs d’évoluer sans un déploiement synchronisé à travers chaque consommateur, ce qui est toute la raison pour laquelle vous avez choisi les événements. La même discipline de versionnage d’interface du chapitre 2.3 s’applique, parce qu’un schéma d’événement est une API sous un autre nom.

Garantir la livraison avec l’outbox transactionnel, et gérer explicitement les pannes

Un bug classique : votre service écrit dans sa base de données puis publie un événement, et il plante entre les deux, donc la base de données a changé mais l’événement n’est jamais sorti. L’outbox transactionnel corrige cela en écrivant l’événement dans une table outbox dans la même transaction de base de données que le changement d’état, pour qu’ils se valident ou échouent ensemble ; un relais séparé lit ensuite l’outbox et publie vers le courtier, utilisant souvent la capture de données modifiées pour suivre le journal de base de données. Pour les pannes de consommation, une file de lettres mortes garde les messages qui échouent de façon répétée pour qu’un message empoisonné (un qui ne réussira jamais, peut-être parce qu’il est malformé) ne bloque pas la file derrière lui pour toujours. Ajoutez de la contre-pression pour qu’un producteur rapide ne puisse pas submerger un consommateur lent : bornez vos files, et ralentissez ou délestez la charge quand elles se remplissent plutôt que d’épuiser la mémoire. Ces quatre mécanismes séparent une démo d’un système que vous pouvez exploiter à 3 heures du matin.

Rendre les flux asynchrones observables de bout en bout

Le coût le plus difficile de devenir piloté par les événements est qu’une seule action d’affaires se disperse maintenant à travers des producteurs, courtiers, et consommateurs sans pile d’appels les liant ensemble. Propagez un ID de corrélation à travers chaque événement pour pouvoir suivre un flux logique unique à travers chaque saut, la même discipline que le chapitre 3.3 prescrit pour les appels synchrones. Suivez le retard de consommateur (à quel point chaque consommateur est en retard sur le temps réel en lecture) comme métrique de premier ordre, parce qu’un retard croissant est votre plus tôt avertissement de problème, et surveillez la profondeur de file de lettres mortes, la latence de traitement, et les taux de relivraison. Sans cela, un événement qui échoue silencieusement à être consommé devient un bug invisible qui surgit des jours plus tard comme des données manquantes.

Compromis : avantages et inconvénients

ApprocheAvantagesInconvénients / coût
Requête/réponse synchroneSimple à raisonner, résultat immédiat, traçage facileCouplage temporel étroit, pannes en cascade, échelle limitée
Piloté par les événements (pub/sub sur un journal)Découplage, échelle indépendante, relecture, piste d’auditCohérence éventuelle, traçage plus difficile, plus de pièces mobiles
File de messages (distribution de travail)Nivellement de charge, mise en tampon, favorable à la contre-pressionUn consommateur par message, moins adapté à la diffusion
Sourcing d’événements + CQRSHistorique complet, requêtes temporelles, lecture/écriture échelonnent indépendammentVersionnage de schéma pour toujours, complexité de relecture, courbe d’apprentissage raide
Saga (contre validation en deux phases)Évolutive, disponible, pas de verrous distribuésCohérence éventuelle, logique de compensation, plus difficile à raisonner

La tension centrale est entre le découplage et la compréhensibilité. Chaque événement que vous ajoutez desserre le couplage entre producteur et consommateur, achetant l’autonomie d’équipe et l’échelle indépendante, et en même temps il retire une ligne de l’histoire qu’un appel synchrone vous aurait dite clairement : le flux devient émergent, vivant dans les interactions plutôt que dans un fichier unique. Résolvez cela en étant sélectif : utilisez les événements là où le découplage rapporte vraiment, comme l’intégration à travers les frontières d’équipe, la diffusion vers de nombreux consommateurs, la mise en tampon des pics de charge, et l’audit. Gardez les appels synchrones là où vous avez besoin d’une réponse immédiate et d’un modèle mental simple, comme lire des données pour rendre une page. Le mode d’échec à éviter est de transformer chaque appel de fonction interne en événement et de l’appeler architecture, le même jugement architectural que le chapitre 3.2 demande de chaque motif que vous adoptez.

Questions à discuter avec votre équipe

  1. Pour cette interaction spécifique, avons-nous réellement besoin d’un événement, ou un appel synchrone serait-il plus clair et plus sûr ? Sauter cette question est comment un système accumule de la complexité accidentelle. Le vrai test est de savoir si le producteur a besoin d’un résultat immédiatement (un appel) ou annonce un fait auquel d’autres peuvent réagir selon leur propre temps (un événement). Apportez l’interaction spécifique, pas une préférence générale, et demandez quel découplage vous gagnez et quelle clarté de traçage vous abandonnez. Si l’appelant bloque en attendant que l’« événement » soit traité, vous avez construit un appel synchrone lent et difficile à déboguer et payé extra pour le privilège. La valeur par défaut pour les interactions internes, même-équipe, besoin-de-la-réponse-maintenant devrait être un appel direct ; réservez les événements pour où le couplage lâche mérite son coût.

  2. Que se passe-t-il quand un consommateur reçoit le même événement deux fois, et l’avons-nous réellement testé ? La livraison au-moins-une-fois garantit que des doublons se produiront, donc chaque consommateur doit être idempotent, pourtant l’idempotence est facile à revendiquer et facile à mal faire. Parcourez un vrai consommateur et tracez exactement comment une seconde livraison est reconnue et neutralisée, que ce soit par une clé d’idempotence, un journal d’événements traités, ou une opération naturellement idempotente. Apportez les résultats d’un vrai test où vous relivrez un lot et confirmez aucune facturation dupliquée, enregistrement dupliqué, ou notification répétée. Portez une attention particulière aux effets de bord qui quittent votre base de données, tels que les e-mails, les paiements, et les appels tiers, parce que ce sont là où les bugs non idempotents blessent directement les clients. Si votre équipe ne peut pas pointer vers un test qui prouve la sécurité aux doublons, supposez que vous n’êtes pas sûr aux doublons.

  3. Quand un flux d’événements se casse en production, combien de temps avant que nous le remarquions, et pouvons-nous tracer un message de bout en bout ? Les pannes asynchrones sont silencieuses, donc un consommateur qui cesse silencieusement de traiter peut passer inaperçu jusqu’à ce que des données manquantes deviennent une plainte client ou une lacune d’audit. Demandez quel est votre plus tôt signal, et si vous surveillez le retard de consommateur et la profondeur de file de lettres mortes comme métriques d’alerte plutôt que des tableaux de bord que personne ne regarde. Apportez un vrai incident ou un exercice de journée de jeu et chronométrez combien de temps il faut pour suivre un seul ID de corrélation à travers le producteur, le courtier, et chaque consommateur. Si la réponse est « nous faisons du grep dans plusieurs services et devinons », votre observabilité n’est pas prête pour la complexité que vous avez prise. Dans les secteurs régulés, pouvoir reconstruire exactement comment un message a bougé est souvent une exigence de conformité, pas une commodité.

  4. Comment ferons-nous évoluer un schéma d’événement que de nombreuses équipes consomment déjà sans en casser aucune ? La forme d’un événement est un contrat public, et une fois que des dizaines de consommateurs en dépendent, un changement d’apparence innocente peut casser des systèmes dont vous n’avez jamais entendu parler, à distance, sans compilateur pour vous avertir. La tension est réelle : les producteurs veulent bouger vite et nettoyer leurs événements, tandis que chaque consommateur veut la forme gelée pour toujours, donc convenez à l’avance de quels changements sont sûrs (ajouter un champ optionnel) et lesquels exigent une nouvelle version et une fenêtre de migration (retirer un champ, changer un type, renommer). Apportez la vraie liste de consommateurs par topic, si un registre de schéma impose des règles de compatibilité aujourd’hui ou si les formes changent par accord informel, et combien de temps deux versions peuvent fonctionner en parallèle pendant une migration. Dans une grande entreprise ou un arrangement gouvernemental de partage de données à travers des agences, un schéma silencieusement cassé peut corrompre des enregistrements dans des systèmes que vous ne possédez pas et surgir plus tard comme un échec d’audit, donc traitez l’imposition de compatibilité comme de la gouvernance, pas de la politesse.

  5. Pour notre transaction multi-service la plus importante, que défait réellement chaque action compensatoire, et quels états intermédiaires les utilisateurs et auditeurs verront-ils ? Les sagas échangent l’illusion confortable d’une transaction atomique unique contre une séquence d’étapes locales qui peuvent chacune échouer, donc le système passe vraiment par des états comme « réservé mais non payé » et « facturé mais non expédié » avant de converger, et prétendre le contraire est comment vous livrez une saga qui fuit de l’argent ou orpheline des enregistrements. Parcourez le vrai processus de bout en bout, nommez la compensation pour chaque étape (ce qui libère l’inventaire, ce qui rembourse la carte), et décidez si une saga orchestrée que vous pouvez surveiller bat une chorégraphie émergente que nul endroit unique ne décrit. Apportez les cas d’échec que vous avez réellement testés, pas le chemin heureux, et confirmez que l’expérience utilisateur et la piste d’audit montrent honnêtement les états « en cours » et « compensé » plutôt que de les cacher. En finance, prestations, ou systèmes fiscaux, un régulateur demandera à quoi ressemblait l’enregistrement à chaque moment intermédiaire et qui était responsable de la compensation, donc les états de la saga sont eux-mêmes un artefact de conformité.

  6. Qui exploite le courtier ou le journal d’événements, et avons-nous compté le vrai coût de l’exploiter contre une alternative gérée ? L’épine dorsale de messagerie n’est pas une infrastructure gratuite qui apparaît une fois que vous la dessinez sur un diagramme : quelqu’un la corrige, échelonne ses partitions, règle la rétention, répond quand elle sonne à 3 heures du matin, et possède sa capacité et ses modes de défaillance. Décidez délibérément entre auto-héberger un courtier open source et acheter un service géré, pesant le contrôle et la résidence des données contre le fardeau opérationnel et le coût de licence, et soyez honnête sur si votre équipe a la profondeur pour bien exploiter un journal distribué. Apportez le coût total de possession : la charge d’astreinte, les compétences spécialisées requises, la facture de rétention et de stockage, et ce qu’une panne de courtier fait à chaque flux dépendant. Pour une entreprise, la réponse façonne le mandat d’une équipe de plateforme, et pour un organisme gouvernemental, les règles d’approvisionnement, les exigences de souveraineté des données, et un vrai besoin d’éviter l’enfermement fournisseur peuvent l’emporter sur l’option la moins chère, donc faites surgir ces contraintes avant de vous engager envers une technologie que vous exploiterez pendant une décennie.

Regard sectoriel

Jeune pousse. Votre ressource la plus rare est l’attention d’ingénierie, donc restez synchrone jusqu’à ce que la diffusion fasse réellement mal. Quand trois choses doivent réagir à une action, publiez un seul événement (comme « CommandePassée ») vers une file ou un journal géré plutôt que de monter votre propre cluster de courtier, et gardez le paiement et tout ce dont vous avez besoin d’une réponse immédiate comme un appel direct. N’adoptez pas le sourcing d’événements, CQRS, ou les sagas pour paraître sophistiqué ; cette complexité dépassera une petite équipe et ralentira l’itération même sur laquelle vous êtes en compétition.

Petite entreprise. Vous n’avez pas de spécialiste de messagerie et aucun appétit pour exploiter Kafka, donc traitez l’intégration asynchrone comme quelque chose que vous achetez, pas exploitez. Appuyez-vous sur les événements que vos outils existants émettent déjà (webhooks, les files intégrées dans votre fournisseur cloud ou plateformes SaaS) et laissez un service géré posséder la livraison, la rétention, et la plomberie d’idempotence. Cadrez le choix comme acheter-contre-construire honnêtement : une poignée de gestionnaires de webhook fiables bat un courtier sur mesure que vous ne pouvez pas doter en personnel ou déboguer à 3 heures du matin.

Grande entreprise. Votre problème est le coût d’intégration à travers de nombreuses équipes, donc le gain est une plateforme partagée gouvernée : un journal d’événements durable, un registre de schéma avec une politique de compatibilité imposée, une propriété de topic claire, et des motifs standard d’idempotence et d’outbox pour qu’aucune équipe ne les réinvente. C’est le contexte où remplacer un bus de service d’entreprise fragile ou une toile de liens point-à-point se compose en économies réelles, et où des sagas orchestrées avec un statut visible permettent au personnel opérationnel de gérer des processus multi-étapes. Budgétez explicitement l’investissement d’observabilité et de gouvernance de schéma, parce qu’à cette échelle une panne silencieuse de consommateur devient des données manquantes à travers des dizaines de systèmes.

Gouvernement. Un journal d’événements durable et ordonné est un actif d’audit et de transparence : il répond « pourquoi cette décision est-elle sortie ainsi » avec une séquence immuable de faits, donc penchez vers le sourcing d’événements là où la redevabilité l’exige. Le partage de données inter-agences a besoin d’une livraison au-moins-une-fois avec déduplication sur un ID d’événement stable pour qu’un enregistrement relivré ne crée jamais un dossier dupliqué, et l’approvisionnement devrait peser la souveraineté des données, la divulgation des limitations d’un courtier, et la portabilité contre l’enfermement. Publiez, là où approprié, comment le flux fonctionne et comment un citoyen peut contester un résultat automatisé, et gardez le journal d’événements comme l’enregistrement défendable que les organes de contrôle demanderont à inspecter.

Exemples

Jeune pousse. Une petite start-up de commerce électronique commence avec un flux synchrone : le paiement appelle le service de paiement et attend. À mesure qu’elle grandit, elle veut des e-mails de confirmation de commande, des mises à jour d’inventaire, et un programme de fidélité pour réagir aux achats, et câbler chacun comme un autre appel synchrone à l’intérieur du paiement rend le paiement lent et fragile. L’équipe publie un seul événement « CommandePassée » vers un journal durable et laisse trois consommateurs indépendants réagir, si bien que le paiement redevient rapide et qu’ajouter une quatrième réaction plus tard n’a besoin d’aucun changement à lui. Elle garde la capture de paiement synchrone, parce qu’elle a besoin de la réponse oui-ou-non avant de confirmer la commande, ce qui est exactement la bonne ligne à tracer à leur taille.

Grande entreprise. Un assureur mondial se noie dans des intégrations point-à-point et un bus de service d’entreprise (ESB) vieillissant, un hub central à travers lequel chaque système route et qui est devenu un goulot d’étranglement et un point de défaillance unique. Il migre vers un journal d’événements durable où chaque domaine publie ses faits (police émise, sinistre déposé, paiement effectué) et les équipes consommatrices s’abonnent à ce dont elles ont besoin. Une saga de sinistres, orchestrée pour que le personnel opérationnel puisse voir le statut de chaque sinistre, coordonne le règlement multi-étapes avec des compensations pour les étapes qui échouent. Un registre de schéma permet à l’équipe de polices de faire évoluer leurs événements sans un déploiement synchronisé à travers quarante systèmes consommateurs, précisément la fragilité que l’ancien ESB imposait.

Gouvernement. Une administration fiscale nationale doit donner aux citoyens et auditeurs une réponse défendable à « pourquoi mon évaluation est-elle sortie ainsi ». Elle modélise le domaine d’évaluation avec le sourcing d’événements, si bien que chaque changement est un événement immuable dans un journal ordonné et l’évaluation actuelle est une relecture de ces événements ; quand un citoyen conteste un chiffre, un agent de dossier reconstruit l’état exact à toute date passée et montre la séquence de faits qui l’a produit. Le partage de données inter-agences fonctionne sur des topics durables avec livraison au-moins-une-fois, et le consommateur de chaque agence déduplique sur un ID d’événement pour qu’un enregistrement relivré ne crée jamais un dossier dupliqué. Le journal d’événements sert aussi de piste d’audit que les organes de contrôle exigent, transformant une obligation de conformité en sous-produit de la conception.

Argumentaire économique : motivations, retour sur investissement et coût total de possession

Le retour sur l’architecture pilotée par les événements est dominé par une chose : le coût de l’intégration dans le temps. L’intégration point-à-point fait croître ce coût avec le nombre de connexions, qui croît plus vite que le nombre de systèmes, donc l’intégration devient la taxe qui mange votre capacité de livraison. Les événements aplatissent cela, parce que les équipes s’intègrent à travers un flux partagé de faits, un nouveau consommateur se joint en s’abonnant, et les producteurs évoluent derrière un schéma versionné, donc le coût marginal de la prochaine intégration chute nettement. C’est l’histoire centrale de retour sur investissement à raconter à la direction : pas la performance brute, mais la réduction cumulée du coût du changement à travers de nombreuses équipes.

Nommez honnêtement le coût total de possession pour être cru. Vous prenez en charge une infrastructure de courtier à exploiter, une gouvernance de schéma à maintenir, et une courbe d’apprentissage opérationnelle plus raide, parce que les systèmes asynchrones sont réellement plus difficiles à déboguer, donc budgétez l’investissement d’observabilité en amont. Pesez cela contre le coût de ne pas adopter les événements là où ils conviennent : une couche d’intégration ossifiée où chaque changement est un projet de coordination multi-équipes, un ESB hérité devenu un goulot d’étranglement que personne n’ose toucher, et une incapacité d’ajouter des capacités sans perturber les anciennes. Pour l’entreprise remplaçant un câblage point-à-point fragile et le gouvernement construisant des pistes d’audit durables, le gain est le plus fort là où les besoins d’audit et de découplage sont réels. Là où ces besoins sont absents, la réponse honnête est qu’une conception synchrone plus simple a le CTP le plus bas, et vous devriez le dire.

Anti-patterns et pièges

  • Le monolithe distribué déguisé. Des services qui doivent tous se déployer ensemble et dépendent des événements internes des uns des autres. Vous avez ajouté un courtier mais gardé le couplage, donc vous avez les inconvénients des deux styles.
  • Événements comme commandes. Publier des « événements » qui signifient vraiment « veuillez faire cette chose spécifique pour moi », recréant un couplage étroit avec de la latence supplémentaire et une pire traçabilité.
  • Supposer la livraison exactement une fois. Des consommateurs qui se cassent, facturent deux fois, ou dupliquent des enregistrements quand le courtier relivre inévitablement un message.
  • Sourcing d’événements partout. Appliquer le sourcing d’événements et CQRS à des domaines simples créer-lire-mettre-à-jour-supprimer qui n’ont jamais eu besoin d’historique, achetant une complexité raide pour aucun bénéfice.
  • Aucune gouvernance de schéma. Des producteurs changeant librement les formes d’événement, cassant des consommateurs en aval à distance sans vérifications de compatibilité.
  • Ignorer l’outbox. Écrire dans la base de données et publier un événement comme deux étapes séparées, si bien qu’un plantage entre les deux perd silencieusement des événements ou en émet des fantômes.
  • Aucune gestion de lettre morte. Un seul message empoisonné bloquant une partition, ou des messages échoués disparaissant sans file pour les attraper et les inspecter.
  • Flux invisibles. Traitement asynchrone sans ID de corrélation, sans alertes de retard de consommateur, et sans traçage, donc les pannes restent silencieuses jusqu’à devenir des données manquantes.

Modèle de maturité

  • Niveau 1 (Initier) : L’intégration est des appels point-à-point ad hoc, ou un courtier existe mais est utilisé comme une requête/réponse synchrone. Les doublons cassent les consommateurs, il n’y a pas de discipline de schéma ni de traçage inter-saut, et les messages échoués disparaissent silencieusement.
  • Niveau 2 (Développer) : Un courtier ou journal est en usage réel pour certains flux, et quelques équipes ont des pratiques de base : les consommateurs deviennent idempotents et les files de lettres mortes attrapent certaines pannes. Mais l’approche est incohérente à travers les équipes, les événements et commandes sont encore mélangés, les schémas changent par accord informel, et l’observabilité est mince.
  • Niveau 3 (Standardiser) : Les événements, commandes, et messages sont distingués délibérément à travers l’organisation. Les consommateurs sont idempotents par norme, les schémas vivent dans un registre avec une politique de compatibilité documentée et imposée, et l’outbox transactionnel garantit la livraison. Les sagas avec compensations gèrent les transactions multi-services, les ID de corrélation se propagent à travers chaque saut, et ces motifs sont consignés et appliqués de façon cohérente plutôt que laissés à chaque équipe.
  • Niveau 4 (Gérer) : La plateforme d’événements est mesurée et contrôlée avec des données par rapport à des références. Le retard de consommateur, la profondeur de file de lettres mortes, les taux de relivraison, et la latence de traitement sont suivis comme métriques d’alerte avec des seuils convenus, pas des tableaux de bord que personne ne regarde ; la compatibilité de schéma est vérifiée automatiquement avant qu’un producteur ne puisse livrer un changement ; la relecture, la gestion de panne, et l’idempotence sont testées selon une cadence fixe plutôt qu’espérées. Si une interaction donnée devrait être un événement ou un appel synchrone est décidé sur preuve, et la capacité, le coût de rétention, et la fiabilité de chaque courtier sont révisés contre des cibles.
  • Niveau 5 (Orchestrer) : Les styles pilotés par les événements et synchrones sont choisis par interaction comme une seconde nature, et le sourcing d’événements et CQRS sont appliqués précisément là où les besoins d’audit et de requête le justifient et nulle part ailleurs. Les flux asynchrones sont aussi observables que les synchrones, la plateforme s’améliore continuellement à mesure que les besoins changent (retirant les topics morts, faisant évoluer la gouvernance de schéma, rééquilibrant les partitions), et la messagerie est intégrée à l’architecture et la stratégie d’audit plus larges pour que l’organisation adapte sa conception d’événements à mesure que l’affaire et ses obligations changent.

Pistes de réflexion

  1. Lesquels de vos « événements » actuels sont secrètement des commandes, et quel couplage retireriez-vous en les modélisant honnêtement ?
  2. Si vous rejouiez une journée complète d’événements à travers vos consommateurs demain, qu’est-ce qui casserait, et que cela vous dit-il sur votre idempotence et votre sécurité de relecture ?
  3. Quelles parties de votre domaine ont vraiment besoin de la piste d’audit du sourcing d’événements, et lesquelles sont un état simple que vous ne feriez que compliquer en le sourçant ?
  4. Comment migreriez-vous hors d’un bus de service d’entreprise hérité ou d’une toile d’intégrations point-à-point sans une bascule risquée à grand fracas ?
  5. Pour votre processus multi-service le plus important, est-ce une vraie saga orchestrée avec compensations, ou une chorégraphie émergente que nul endroit unique ne décrit ?

Points clés à retenir

  • L’architecture pilotée par les événements achète le découplage, l’échelle indépendante, la relecture, et les pistes d’audit, et elle coûte de la compréhensibilité et de la complexité opérationnelle, donc choisissez-la par interaction là où le bénéfice est réel.
  • Gardez distincts les événements (faits qui se sont produits), les commandes (requêtes d’agir), et les messages (l’enveloppe), parce que la confusion cause de vraies erreurs de couplage.
  • Concevez pour la livraison au-moins-une-fois et rendez chaque consommateur idempotent ; la livraison exactement une fois est un mythe, et les effets exactement une fois sont un exploit d’ingénierie.
  • L’ordonnancement est par partition, les schémas sont des contrats qui appartiennent à un registre, et l’outbox, les files de lettres mortes, et la contre-pression sont la plomberie qui rend la messagerie prête pour la production.
  • Utilisez des sagas avec compensations au lieu de la validation en deux phases, et recourez au sourcing d’événements et CQRS seulement là où les besoins d’audit et de requête justifient leur coût raide.
  • Les flux asynchrones sont silencieux quand ils échouent, donc les ID de corrélation, la surveillance du retard de consommateur, et le traçage de bout en bout sont la différence entre un système exploitable et un invisible.

Références et lectures complémentaires

  • Martin Kleppmann, Designing Data-Intensive Applications
  • Gregor Hohpe et Bobby Woolf, Enterprise Integration Patterns
  • Chris Richardson, Microservices Patterns (sagas, outbox transactionnel, CQRS)
  • Sam Newman, Building Microservices
  • Ben Stopford, Designing Event-Driven Systems
  • Adam Bellemare, Building Event-Driven Microservices
  • Vaughn Vernon, Implementing Domain-Driven Design (sourcing d’événements et CQRS)
  • Martin Fowler, « Event Sourcing » et « CQRS » (articles martinfowler.com)
  • Hector Garcia-Molina et Kenneth Salem, « Sagas » (1987)