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.

flowchart LR CL["Client externe"] --> GW["Passerelle d'API"] GW --> APP["Service applicatif"] APP --> CACHE[("Cache")] APP --> DB[("Base de données")] APP -->|"Message : une instruction"| SB["Service Bus"] APP -->|"Événement : un fait"| EG["Event Grid"] APP -->|"Flux : de la télémétrie"| EH["Event Hubs"] SB --> W1["Traitement métier"] EG --> W2["Fonction déclenchée"] EH --> W3["Traitement de flux"] classDef edge fill:#b5651d,stroke:#8a4d16,color:#f5f2ec classDef core fill:#d89253,stroke:#8a4d16,color:#1a1a1a classDef back fill:#ede9e1,stroke:#8a4d16,color:#2c3338 class CL,GW edge class APP,SB,EG,EH core class CACHE,DB,W1,W2,W3 back

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.

sequenceDiagram participant P as Producteur participant Q as File Service Bus participant C as Consommateur participant D as Lettres mortes P->>Q: Dépose le message 42 Q->>C: Livraison 1, verrou posé C--xQ: Traitement fait, acquittement perdu Q->>C: Livraison 2 du message 42 C->>C: Clé déjà vue, on ignore le doublon C->>Q: Acquittement Note over Q,D: Message 77, rejeté à chaque tentative Q->>D: Mise de côté après la 5e livraison

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.


Pour aller plus loin