Le portique attend, le centre de tri non
Sur le terminal, deux gestes cohabitent et ne se ressemblent pas.
Le portique décharge un conteneur et attend l'accusé du cariste. Tant que la réponse n'arrive pas, la grue ne bouge plus. Un maillon lent bloque toute la chaîne.
À cinquante mètres, le centre de tri reçoit les bordereaux, les range dans des casiers et passe au suivant. Personne ne reste planté devant un casier en attendant qu'il se vide. Le rythme d'arrivée et le rythme de traitement sont découplés, volontairement.
Le billet précédent, Répartition de charge et sécurité réseau, a traité l'aiguillage du trafic entrant vers le bon quai. Celui-ci descend d'un cran : une fois le navire à quai, il reste à savoir comment les composants se parlent, comment on présente les API vers l'extérieur, et où l'on pose la consigne.
Trois briques, trois questions distinctes : par quel canal circule l'information, qui a le droit d'entrer par la porte publique, et quelles données on refuse de recalculer.
Vue d'ensemble : message, événement, flux
Au centre de tri, un bordereau de livraison et un avis de passage ne servent pas à la même chose. Le premier ordonne un travail précis à quelqu'un de désigné. Le second signale qu'un fait s'est produit, à qui veut bien le lire.
Cette distinction porte tout le reste du billet, et l'ignorer coûte cher. Un message est une instruction avec une intention : l'émetteur veut que quelque chose soit fait. Un événement est un fait déjà survenu : l'émetteur n'attend rien et ne connaît pas ses lecteurs.
| Critère | Message | Événement |
|---|---|---|
| Nature | Une instruction, avec une intention | Un fait, déjà accompli |
| Attente de l'émetteur | Qu'un consommateur le traite | Aucune |
| Charge utile | Complète, elle fait partie du contrat | Légère, souvent un identifiant et un état |
| Couplage | L'émetteur sait qu'un traitement doit suivre | L'émetteur ignore qui écoute |
| Si personne ne consomme | C'est une anomalie à traiter | C'est un cas normal |
| Services Azure typiques | File de stockage, Service Bus | Event Grid, Event Hubs |
À cela s'ajoute une troisième forme, le flux : des événements de même nature, produits en continu et en grand nombre, qu'on traite par fenêtres plutôt qu'un par un. La télémétrie, les journaux et les clics relèvent de ce régime.
Le schéma suivant place les briques les unes par rapport aux autres. La passerelle garde la porte publique, le cache évite les allers-retours, et les trois canaux asynchrones partent vers la droite.
La suite déroule ces briques dans l'ordre : les quatre services de communication, les garanties réelles qu'on obtient d'eux, la passerelle d'API, le cache applicatif et le cache de bordure, puis la configuration centralisée.
Avant de choisir un service, il faut savoir si l'on produit une instruction, un fait ou un flux. Le catalogue Azure ne répond à rien tant que cette question reste ouverte.
Les quatre canaux de communication
Le port n'a pas un seul système de circulation de l'information. Il a un casier pour les ordres simples, un bureau de tri pour les envois qui engagent, un tableau d'affichage pour les avis, et un compteur de passage qui enregistre tout sans distinction.
La file de stockage
C'est le casier. Un composant du compte de stockage, sans cérémonie : on dépose un message, un consommateur le retire, le traite et le supprime.
Le message y est petit, quelques dizaines de kilo-octets au plus, mais la file peut accumuler un volume considérable, à hauteur de la capacité du compte de stockage. Il n'y a ni rubriques, ni sessions, ni transactions, ni ordre garanti.
Elle se justifie quand deux composants doivent se découpler sans autre exigence, et que l'équipe gère déjà un compte de stockage. Sa faiblesse est aussi son intérêt : elle ne propose presque rien, donc rien à mal configurer.
Service Bus
C'est le bureau de tri, celui qui délivre des bordereaux et en garde la trace. Un courtier de messages d'entreprise, avec la sémantique qui va avec.
Deux formes coexistent. La file, où un message est consommé par un seul destinataire. La rubrique et ses abonnements, où le même message est copié vers plusieurs destinataires, chacun pouvant filtrer ce qu'il reçoit par une règle évaluée côté courtier.
S'y ajoutent les mécanismes qui font la différence en production : les sessions, qui rétablissent un ordre strict pour une même clé métier, la détection de doublons sur une fenêtre de temps, les messages différés, les transactions sur plusieurs opérations du même espace de noms, et la file de lettres mortes attachée à chaque file.
Le niveau Premium change la nature du service plus qu'on ne le croit : ressources dédiées, intégration au réseau virtuel, redondance de zone et messages nettement plus volumineux qu'en Standard.
Event Grid
C'est le tableau d'affichage. Un événement discret est publié, et le service se charge de le distribuer à tous ceux qui se sont déclarés intéressés.
Le modèle est inversé par rapport à une file : ce n'est pas le consommateur qui vient chercher, c'est le service qui pousse vers un point de terminaison, une fonction, une file ou un connecteur logique. Le filtrage se fait à l'abonnement, sur le type d'événement, le sujet ou les attributs.
Deux points comptent en conception. D'abord, les nouvelles tentatives sont automatiques, avec un délai croissant ; un événement jamais remis finit dans un espace de lettres mortes qu'il faut avoir prévu. Ensuite, la charge utile est une notification, pas une donnée : le consommateur revient chercher l'état complet à la source.
Event Hubs
C'est le compteur de passage du portail principal, qui enregistre tout ce qui entre sans se demander qui viendra lire.
Un journal partitionné, conçu pour l'ingestion à très fort débit. Les événements sont écrits dans des partitions, conservés pendant une fenêtre de rétention, et relus par des groupes de consommateurs indépendants qui avancent chacun à leur rythme. Un point de terminaison compatible avec le protocole Kafka permet de brancher un écosystème existant sans le réécrire.
La différence de fond avec Service Bus tient en une phrase : ici, la lecture n'efface rien. Le même flux peut alimenter un traitement temps réel, une archive et un rejeu de correction.
| Critère | File de stockage | Service Bus | Event Grid | Event Hubs |
|---|---|---|---|---|
| Modèle | File simple | Files et rubriques | Distribution poussée | Journal partitionné |
| Ordre | Aucune garantie | Strict par session | Aucune garantie | Garanti dans une partition |
| Débit visé | Modéré | Modéré, sémantique riche | Réaction événementielle | Ingestion massive |
| Relecture | Impossible | Hors lettres mortes, non | Non, rejeux automatiques | Oui, dans la rétention |
| Filtrage côté service | Aucun | Règles d'abonnement | Type, sujet, attributs | Aucun, le lecteur trie |
| Utile pour | Découpler sans exigence | Commandes métier fiables | Réagir à un changement d'état | Télémétrie, journaux, clics |
La question qui tranche n'est presque jamais le débit. Elle est double : quelqu'un devra-t-il relire ce qui est passé, et un traitement raté doit-il laisser une trace exploitable.
Les garanties qu'on croit avoir
Un bordereau remis en main propre au cariste ne garantit pas que la palette soit déplacée. Il garantit que quelqu'un l'a reçu.
Trois croyances reviennent dans tous les projets, et les trois sont fausses telles quelles.
L'ordre. Aucun de ces services ne garantit un ordre global. Service Bus l'assure à l'intérieur d'une session, Event Hubs à l'intérieur d'une partition. Dès que le parallélisme entre, l'ordre sort. La bonne question n'est pas « comment tout ordonner » mais « quelle clé métier exige un ordre strict ».
La livraison unique. Le régime réel est la livraison au moins une fois. Un accusé perdu, un verrou expiré, un consommateur redémarré au mauvais moment suffisent à provoquer une seconde livraison du même message. Le consommateur doit être idempotent, avec une clé stable stockée quelque part, sans quoi le client sera débité deux fois.
Le message qui finit toujours par passer. Non. Un message que le traitement rejette systématiquement, faute de format ou de donnée manquante, sera relivré jusqu'à la limite fixée, puis mis de côté. C'est le rôle de la file de lettres mortes, et elle se conçoit au premier jour, pas après le premier incident.
Le paramétrage tient en deux valeurs : la durée du verrou, qui doit couvrir le pire temps de traitement observé, et le nombre maximal de livraisons avant mise à l'écart.
az servicebus queue create \
--resource-group rg-integration \
--namespace-name sb-port-prod \
--name commandes \
--max-delivery-count 5 \
--lock-duration PT1M
Une file de lettres mortes sans alerte ni procédure de reprise est un cimetière. Elle doit être supervisée comme une ressource de production, et quelqu'un doit savoir rejouer son contenu après correction.
Un verrou trop court transforme un traitement lent en tempête de doublons. C'est la cause la plus fréquente des « messages traités deux fois » qu'on impute au courtier.
Présenter les API
Un transitaire qui veut faire entrer une cargaison ne va pas frapper à la porte de chaque grutier. Il passe au guichet des formalités, présente ses papiers, obtient un numéro, et le port décide de la suite.
Azure API Management joue ce guichet. Il place une façade unique devant des services hétérogènes, applique des règles avant de laisser passer, et rend l'organisation interne invisible depuis l'extérieur.
Le cœur du service, ce sont les stratégies : des règles déclaratives évaluées en entrée, en sortie ou en cas d'erreur. Validation de jeton, limitation de débit, réécriture d'URL, transformation de charge utile, mise en cache de réponse, tout se pose là plutôt que dans chaque service.
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="401">
<openid-config url="https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration" />
</validate-jwt>
<rate-limit-by-key calls="100" renewal-period="60"
counter-key="@(context.Subscription.Id)" />
</inbound>
Autour de ces stratégies, deux notions structurent la publication. Le produit regroupe un ensemble d'API avec ses conditions d'accès, l'abonnement matérialise le droit d'un consommateur sur un produit. Le portail développeur expose la documentation et permet de demander une clé sans passer par une boîte aux lettres partagée.
Les niveaux de service se lisent sur trois axes : la disponibilité annoncée, l'intégration au réseau virtuel et la capacité multi-région. Le niveau de développement n'a pas d'engagement de disponibilité et ne doit pas se retrouver en production. Le niveau Premium apporte le déploiement multi-région et la passerelle auto-hébergée, celle qu'on installe dans son propre centre de données ou dans un cluster de conteneurs pour exposer une API interne sans ouvrir de flux entrant.
| Besoin | Ce qui répond dans la passerelle | L'erreur classique |
|---|---|---|
| Contenir un client bruyant | Limitation par clé et quota d'abonnement | Compter par adresse IP derrière un NAT |
| Vérifier l'appelant une seule fois | Validation du jeton en entrée | Laisser chaque service revalider à sa façon |
| Masquer une refonte interne | Réécriture d'URL et transformation | Publier la forme interne comme contrat |
| Servir plusieurs publics | Produits et abonnements distincts | Un produit unique pour tout le monde |
| Exposer une API restée sur site | Passerelle auto-hébergée | Percer un flux entrant vers l'interne |
La passerelle est un point de passage obligé, donc un point de panne et un point de coût. On y met ce qui doit être commun à toutes les API, et rien d'autre.
Le cache, ou la consigne du port
À la sortie du terminal, la consigne évite d'aller rechercher la même caisse au fond de l'entrepôt douze fois par jour. Elle ne remplace pas l'entrepôt : elle en rapproche ce qu'on redemande souvent.
Azure Cache for Redis rend ce service côté applicatif. Le motif de loin le plus répandu reste le cache de côté : l'application lit d'abord le cache, va chercher à la source en cas d'absence, puis écrit dans le cache avec une durée de vie.
Ce qu'on y met : des résultats de calcul coûteux, des données de référence peu changeantes, des sessions, des jetons de limitation de débit, des verrous répartis. Ce qu'on n'y met pas : la source de vérité d'une donnée qu'on ne sait pas reconstruire, et des données personnelles qu'on ne saurait pas purger sur demande.
L'effet sur la charge se calcule, et le résultat surprend souvent.
Requêtes entrantes : 10 000 /s
Taux de succès du cache : 95 %
Charge atteignant la base : 500 /s
Si le taux tombe à 80 % : 2 000 /s, soit quatre fois plus
Un cache qui perd quinze points de succès quadruple la charge de la base. C'est exactement ce qui se produit après un vidage complet, ou quand un grand nombre de clés expirent au même instant. D'où deux réflexes : ne jamais poser la même durée de vie sur des milliers de clés créées ensemble, et prévoir le comportement de l'application quand le cache est indisponible.
Les niveaux vont du cache de développement, sans engagement de disponibilité, à ceux qui offrent réplication, redondance de zone, persistance et intégration réseau, puis à ceux adossés au moteur d'entreprise. La règle de dimensionnement tient à trois grandeurs : la taille des données, le débit d'opérations et la bande passante réseau de l'instance.
Le second cache est ailleurs, en bordure du réseau, sur les points de présence proches des clients. Front Door y assume aujourd'hui à la fois la répartition mondiale et la diffusion de contenu. On y met les réponses HTTP entières et les fichiers statiques, et l'on y gagne de la latence et de la bande passante de sortie.
| Question | Cache applicatif | Cache de bordure |
|---|---|---|
| Ce qu'il stocke | Objets, sessions, résultats de requêtes | Réponses HTTP et fichiers statiques |
| Où il se trouve | Dans la région, près du service | Aux points de présence, près du client |
| Qui décide | Le code applicatif | Les en-têtes de cache et les règles de routage |
| Ce qu'il économise | Des accès à la base de données | De la latence et de la sortie de données |
| Invalidation | Par clé ou par durée de vie | Purge de chemins, empreinte dans l'URL |
La difficulté d'un cache n'est jamais de le remplir. Elle est de décider quand son contenu devient faux, et ce que l'application fait pendant qu'il est vide.
La configuration et les bascules de fonctionnalité
Le règlement d'exploitation d'un terminal n'est pas repeint sur la grue à chaque changement d'horaire. Il tient dans un classeur unique que tout le monde consulte.
Azure App Configuration joue ce classeur : un magasin central de paramètres, étiquetables par environnement, avec un historique et des points de restauration. Il sait référencer un secret conservé dans un coffre plutôt que d'en héberger la valeur, sujet traité au billet suivant. Il porte aussi les bascules de fonctionnalité, qui permettent d'activer un comportement pour une partie des utilisateurs et de le désactiver sans redéployer.
Une bascule de fonctionnalité est un interrupteur de secours autant qu'un outil de livraison progressive. Encore faut-il que la coupure du magasin de configuration ne coupe pas l'application avec elle.
Scénario B : la panne Datadog du 8 mars 2023
Datadog a publié un compte rendu détaillé de la panne qui a frappé sa plateforme le 8 mars 2023. Il tombe exactement sur le sujet de ce billet.
Le déclencheur est banal : une mise à jour de sécurité d'un composant système, appliquée automatiquement sur les nœuds. Son effet ne l'est pas. Elle a coupé la connectivité réseau des machines concernées, mettant hors service des dizaines de milliers de nœuds à peu près au même moment, répartis sur plusieurs régions et chez plusieurs fournisseurs de cloud.
Le point remarquable est là. Ces nœuds n'avaient aucun lien logique entre eux, ils appartenaient à des environnements différents et à des infrastructures différentes. Ils partageaient une seule chose : le même mécanisme de mise à jour automatique, avec la même faiblesse au même instant.
C'est la suite qui nous intéresse ici. Une fois la capacité de calcul reconstruite, la panne n'était pas finie. Les traitements arrêtés avaient laissé derrière eux une accumulation considérable de données en attente, et il a fallu à la fois absorber le flux courant et rattraper l'arriéré. L'éditeur décrit le travail d'arbitrage qui en découle : rétablir d'abord l'ingestion en direct, puis rejouer progressivement ce qui s'était accumulé. La remise en état complète s'est étalée bien au-delà du rétablissement du service.
Le découplage a joué son rôle : les données n'ont pas été perdues, elles ont attendu. Mais une file qui se remplit doit être vidée, et cette vidange est un second incident, avec son propre débit, sa propre durée et son propre risque de saturation.
Concevoir une file, c'est aussi concevoir son rattrapage. Si le débit de traitement nominal est à peine supérieur au débit de production, aucune reprise n'est possible dans la fenêtre de rétention.
Points clés
- Message et événement ne sont pas la même chose. Le premier ordonne un travail à quelqu'un, le second constate un fait pour qui veut le lire. Le service se choisit après cette question, pas avant.
- Service Bus pour la sémantique, Event Hubs pour le débit et la relecture, Event Grid pour la réaction, la file de stockage pour le découplage sans exigence. Le débit n'est presque jamais le critère décisif.
- La livraison au moins une fois est le régime réel. L'idempotence du consommateur et la file de lettres mortes se conçoivent au premier jour, avec un verrou plus long que le pire temps de traitement.
- La passerelle d'API centralise ce qui doit être commun : authentification, limitation de débit, transformation, publication. Elle devient de ce fait un point de passage obligé, à dimensionner et à superviser comme tel.
- Un cache se juge sur son taux de succès et sur son comportement à vide. Quinze points de succès perdus multiplient par quatre la charge de la base, et une expiration groupée produit exactement cet effet.
Dans la série
Palier 3 : Faire tourner le port. Domaine : Applications & intégration.
- Précédent : Répartition de charge et sécurité réseau : quatre services, cinq filtres
- Suivant : Sécuriser ses applications : Key Vault, identités managées, chiffrement
- Vue d'ensemble : Concevoir sur Azure : par où commencer
Pour aller plus loin
- Sécuriser ses applications : Key Vault, identités managées, chiffrement, pour la suite logique : ces briques ne doivent porter aucun secret en clair.
- Répartition de charge et sécurité réseau : quatre services, cinq filtres, pour ce qui se passe en amont de la passerelle d'API.
- Comparer les services de messagerie Azure, la page de référence pour départager file, événement et flux.
- Concepts clés d'API Management, pour les produits, abonnements et stratégies.
- Files de lettres mortes de Service Bus, pour les causes réelles de mise à l'écart d'un message.
- Le motif de cache de côté, pour le motif de lecture évoqué dans la section cache.
- Le compte rendu public de Datadog sur l'incident du 8 mars 2023, publié sur son blog, d'où viennent les éléments du scénario B.