Un point d'entrée réglé pour des pages web coupe, retarde ou refuse les flux longs (WebSocket, SSE, gRPC) alors que le service derrière lui fonctionne parfaitement. Cette leçon s'adresse à une personne qui sait déjà publier une application derrière un proxy et qui découvre qu'une notification arrive en retard, qu'une conversation temps réel tombe au bout d'une minute ou qu'un appel gRPC échoue. Elle explique ce qu'est un flux long, pourquoi un proxy le coupe sans panne, et ce que chaque protocole demande de particulier, sans configurer d'outil. Les directives vivent dans les pages de Nginx et d'HAProxy.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »La leçon va de la définition d'un flux long à la façon de le mesurer.
- Distinguer un flux long d'une requête ordinaire, et nommer WebSocket, SSE et gRPC.
- Expliquer pourquoi un délai d'inactivité coupe un flux qui n'est pas cassé.
- Décrire ce que chacun des trois protocoles exige d'un proxy.
- Choisir une borne d'inactivité d'après le battement de l'application (son petit message régulier « je suis vivant ») et non d'après la durée du flux, et reconnaître les bornes dont un battement ne protège pas.
- Prouver qu'un flux circule en chronométrant l'arrivée de chaque message.
Prérequis
Section intitulée « Prérequis »La leçon suppose que vous savez lire un échange HTTP et situer le proxy sur le trajet d'une requête.
- Lire une requête, une réponse, leurs en-têtes et leurs codes de statut : Lire HTTP avant de configurer un proxy.
- Situer le point d'entrée entre l'appelant et l'application : Publier un service web.
- Connaître l'idée de délai et de borne de lecture : Maîtriser délais, tentatives et cache sans altérer les réponses.
Le lab fournit la machine, le service et le client de mesure : vous n'installez rien.
Qu'est-ce qu'un flux long, et en quoi diffère-t-il d'une page ?
Section intitulée « Qu'est-ce qu'un flux long, et en quoi diffère-t-il d'une page ? »Un flux long est une connexion qui reste ouverte pendant que des données y circulent par à-coups, là où une requête ordinaire s'ouvre, reçoit sa réponse et se referme. Un point d'entrée (ou reverse proxy, le serveur placé devant l'application qui relaie les requêtes vers un backend) est conçu pour le second cas. Il suppose qu'une réponse arrive vite, se termine, et qu'une connexion inactive est une connexion morte.
Trois protocoles produisent des flux longs. Un WebSocket est une connexion qui commence comme une requête HTTP, puis bascule, après une poignée de main (un échange initial où le client demande à changer de protocole), en un canal où client et serveur envoient des messages quand ils veulent. Le SSE (Server-Sent Events) est une réponse HTTP qui ne se termine pas : le serveur y écrit des événements au fil du temps, et le client les reçoit un à un. gRPC est un protocole d'appels de procédure à distance qui circule sur HTTP/2, et qui peut lui aussi garder un échange ouvert dans la durée.
Un protocole applicatif est la convention que l'application et son client suivent par-dessus le transport, ici WebSocket, SSE ou gRPC. Le proxy ne le comprend pas toujours, mais il doit le laisser passer. C'est pour cela que les flux longs demandent au proxy autre chose que les pages : le même point d'entrée peut servir parfaitement le site et se tromper sur ces trois routes, chacune pour une raison propre.
| Ce qui change | Une page | Un flux long |
|---|---|---|
| Durée de la connexion | Quelques instants | Minutes, heures |
| Fin de la réponse | La réponse se termine | La réponse ne se termine pas, ou la connexion est un canal |
| Données | Envoyées d'un bloc | Envoyées par à-coups, avec des silences |
| Connexion silencieuse | Signe de panne | Situation normale |
La dernière ligne est celle qui piège le plus. Elle prépare la question suivante.
Pourquoi un point d'entrée coupe-t-il un flux alors que rien n'est en panne ?
Section intitulée « Pourquoi un point d'entrée coupe-t-il un flux alors que rien n'est en panne ? »Un proxy coupe un flux quand aucune donnée n'a circulé pendant le délai qu'il s'est fixé, et non parce que la connexion dure longtemps. Ce délai est une borne d'inactivité. Dans Nginx, proxy_read_timeout en est un exemple ; dans HAProxy, c'est timeout server. La borne repart à zéro à chaque octet reçu : un flux qui émet un message toutes les trente secondes ne tombe jamais sous une borne de soixante secondes, alors qu'un flux silencieux pendant une minute est fermé.
Une borne de durée totale, que certains produits offrent en plus (c'est l'un des trois délais d'une requête dans la leçon Maîtriser délais, tentatives et cache sans altérer les réponses), est d'une autre nature : elle coupe même un flux actif, et le client doit alors se reconnecter. Ce n'est pas elle qui explique un flux silencieux coupé au bout d'une minute.
Le piège vient de ce que, pour une page, ce comportement est exactement ce qu'on veut. Une réponse qui ne donne plus signe de vie est probablement bloquée, et la couper libère la connexion. Pour un flux, le silence est légitime : une application de notifications peut n'avoir rien à dire pendant cinq minutes. Le proxy, qui ne sait pas faire la différence entre un flux calme et un backend bloqué, applique la même règle aux deux.
Le résultat est déroutant. Le service fonctionne, le réseau fonctionne, aucune erreur n'apparaît côté application, et pourtant la connexion tombe, souvent à intervalle régulier, au même nombre de secondes. Cette régularité est l'indice : une coupure qui tombe pile à soixante secondes évoque un délai réglé à cette valeur plutôt qu'un incident. Lisez-la comme un indice, à confirmer en lisant la configuration.
Le cas du WebSocket ajoute une subtilité. Après la réponse 101 Switching Protocols (le code par lequel le serveur accepte de changer de protocole), la connexion devient un tunnel : le proxy relaie désormais des octets sans plus interpréter de HTTP. Dans HAProxy, cette phase relève d'une borne distincte de celle de la lecture de la réponse, timeout tunnel : définie, elle remplace les bornes timeout client et timeout server dès que la connexion est devenue un tunnel, et elle mesure comme elles l'inactivité, dans les deux sens. Dans cet outil, c'est donc elle qu'il faut régler pour un WebSocket, et les autres outils ont chacun leurs propres réglages. Le principe, lui, est commun : toute phase d'une conversation a sa borne, et le tunnel est une phase de plus.
Pourquoi un flux SSE arrive-t-il en bloc au lieu d'au fil de l'eau ?
Section intitulée « Pourquoi un flux SSE arrive-t-il en bloc au lieu d'au fil de l'eau ? »Un proxy qui met la réponse en tampon (buffering) retient les événements d'un flux SSE jusqu'à en avoir assez, et les livre ensemble, trop tard. La mise en tampon consiste à lire la réponse du backend le plus vite possible, à la ranger en mémoire, puis à la distribuer au client à son rythme. Pour une page, c'est en général le bon réglage : le backend est libéré tout de suite et le client lent ne le retient pas.
Pour un flux, c'est le contraire de ce qu'il faut. Le serveur émet un événement par seconde, mais le proxy attend d'avoir rempli son tampon avant d'écrire vers le client. Le client reçoit tous les événements, dans le bon ordre, sans perte, mais en rafale, quand le tampon se vide. Le rythme, qui est la raison d'être d'un flux, a disparu, et un tableau de bord censé afficher des notifications en direct les affiche par paquets.
Ce défaut passe les tests naïfs. Un test qui compte les événements reçus au bout du flux donne un résultat correct avec un proxy qui retient tout, puisque tout finit par arriver. Ce qui distingue un flux d'un lot est le moment de chaque arrivée, pas leur nombre. D'où une règle de mesure qui revient dans toute la leçon : on vérifie un flux en chronométrant chaque message, jamais en lisant un corps final.
Notez aussi que le tampon peut se trouver ailleurs que dans le proxy que vous réglez. Un client qui met lui-même sa lecture en tampon produit le même retard devant un proxy parfaitement configuré : avant d'accuser le point d'entrée, assurez-vous que l'outil de mesure ne retient rien de son côté.
Que demande chaque protocole applicatif à un proxy ?
Section intitulée « Que demande chaque protocole applicatif à un proxy ? »Chaque protocole exige quelque chose de différent : le WebSocket veut qu'on transmette la poignée de main, le SSE qu'on ne retienne rien, gRPC qu'on parle HTTP/2 jusqu'au backend. Le tableau résume ces exigences, puis chaque ligne est expliquée.
| Protocole | Ce qu'il exige du proxy | Symptôme quand c'est absent |
|---|---|---|
| WebSocket | Laisser passer la demande de changement de protocole, puis relayer le tunnel | La connexion ne s'établit pas, ou s'établit sans que rien ne circule |
| SSE | Ne rien retenir, tolérer des silences | Les événements arrivent ensemble, ou la connexion tombe en silence |
| gRPC | Parler HTTP/2 et transmettre les statuts de fin | L'appel échoue au niveau du transport |
Pour le WebSocket, la demande de basculer passe par des en-têtes (Upgrade en particulier) qui décrivent la connexion entre deux maillons voisins et non la requête de bout en bout. Ils sont dits hop-by-hop, et un proxy ne les retransmet pas de lui-même : il faut le lui demander. Sans eux, le backend répond comme à une requête ordinaire et la poignée de main échoue. Même une poignée de main réussie ne prouve que la moitié du chemin : un 101 montre que le backend a accepté, pas que les messages circulent ensuite. Il faut un message qui revient.
Pour le SSE, l'exigence est négative : ne rien mettre en tampon, et ne pas prendre le silence pour une fin. Le flux d'événements est une longue réponse HTTP sans fin prévue. Comme il peut se taire longtemps entre deux changements d'état, il dépend de la borne d'inactivité vue plus haut.
Pour gRPC, deux notions nouvelles. Le HTTP/2 est la version du protocole qui multiplexe plusieurs échanges sur une seule connexion, c'est-à-dire qui les entrelace sans les mélanger. Il sait aussi envoyer des trailers, des en-têtes placés après le corps de la réponse. gRPC y place son statut final. gRPC exige HTTP/2 de bout en bout, jusqu'au backend : un proxy limité à HTTP/1 vers le backend ne sait transporter ni les échanges entrelacés ni les trailers, et l'appel échoue.
Ce dernier point a une conséquence de diagnostic : un appel gRPC refusé par l'application porte un code HTTP 200, et c'est le statut gRPC, dans les trailers, qui dit ce qui s'est passé. Un proxy qui confond les deux fait passer un refus définitif pour une panne passagère, et un client configuré pour rejouer les pannes peut alors rejouer en vain. Les gestes exacts sont dans Nginx : publier WebSocket, SSE et gRPC sans coupure. La page Borner temps, files et flux longs avec HAProxy traite WebSocket et SSE, et laisse gRPC de côté.
Comment choisir une borne : en face du battement ou de la durée ?
Section intitulée « Comment choisir une borne : en face du battement ou de la durée ? »Une borne d'inactivité se règle en face du battement de l'application, c'est-à-dire de l'intervalle entre ses messages réguliers, et non en face de la durée du flux. Le battement (heartbeat, ou ping) est un petit message que l'application envoie à intervalle régulier pour dire qu'elle est vivante, même quand elle n'a rien d'utile à transmettre. En SSE, il prend souvent la forme d'un événement dédié ou d'une ligne de commentaire que le client ignore.
Le raisonnement est le suivant. La borne repart à chaque octet : tant que le battement tombe avant elle, la connexion n'est jamais jugée inactive, même si le flux dure des heures. Régler la borne d'inactivité à la durée attendue de la session, par exemple une heure « pour être tranquille », est donc un mauvais réglage. Cela n'apporte rien si le battement est bien placé, et cela transforme une protection en risque : un backend qui disparaît sans prévenir peut alors garder sa connexion ouverte une heure entière.
La règle pratique se déduit en trois temps. Relevez l'intervalle du battement de l'application, ou à défaut le plus long silence normal. Réglez la borne un peu au-dessus, avec une marge qui absorbe un battement retardé. Appliquez-la à la route du flux seulement, car les pages ordinaires gardent une borne courte qui libère leurs connexions mortes.
Cette règle vaut pour une borne d'inactivité, et seulement pour elle. Un battement ne protège pas d'une borne de durée totale comme celle décrite plus haut, puisque celle-ci compte le temps écoulé sans regarder si des octets circulent. La mesure le montre : sur Traefik 3.7.15, une borne d'écriture de trois secondes coupe un flux SSE qui émet pourtant un événement par seconde, donc jamais silencieux, après trois événements ; la même borne portée à vingt secondes en laisse passer vingt. Avant de régler une borne en face du battement, vérifiez donc laquelle des deux le produit vous offre, ce que Maîtriser santé, délais et flux longs avec Traefik détaille pour ce produit.
Deux précisions de jugement, pour ne pas les prendre pour des faits. D'abord, la marge exacte n'a pas de valeur universelle : elle dépend de la tolérance de l'application à un battement perdu. Ensuite, un battement n'est pas obligatoire pour qu'un flux survive : sans lui, il faut accepter une borne plus longue, au prix d'une détection de panne plus lente. C'est un compromis, pas une règle.
Comment un client sait-il que le flux est mort et non juste silencieux ?
Section intitulée « Comment un client sait-il que le flux est mort et non juste silencieux ? »Un flux silencieux et un flux mort se ressemblent tant que rien ne distingue l'absence de message d'une panne, d'où deux outils : le battement et le signalement explicite de la panne. Du côté du client, un flux sans nouvelle depuis dix secondes peut vouloir dire que l'application n'a rien à dire, ou que le service qui l'alimente est tombé. Aucun octet ne permet de trancher.
Le battement règle la première moitié. Si le serveur émet un battement toutes les quelques secondes, le client sait qu'un silence plus long que cet intervalle n'est plus normal. Un battement dont l'intervalle est réglé à des milliers de secondes ne se déclenche jamais en pratique : il équivaut à aucun battement, et le client reste incapable de distinguer un flux silencieux d'un flux mort.
Le signalement explicite règle la seconde moitié. Quand la source des données tombe, le serveur de flux peut envoyer un événement de panne dédié, puis fermer proprement la connexion. Le client apprend ainsi tout de suite ce qui se passe, au lieu d'attendre un silence qui ne finit pas. Laisser le flux ouvert et muet pour toujours est ce qui renseigne le moins le client : il ne reçoit ni donnée ni explication, et ne peut pas décider de se reconnecter.
Ces deux dispositifs relèvent du service, pas du proxy. Le point d'entrée transmet ce que l'application écrit : un événement de panne doit donc venir d'elle. C'est une bonne raison de lire un incident en deux temps : le proxy a-t-il coupé, ou le service a-t-il cessé d'émettre ? La réponse oriente la correction vers le bon endroit.
Comment prouver qu'un flux fonctionne vraiment ?
Section intitulée « Comment prouver qu'un flux fonctionne vraiment ? »On prouve un flux en chronométrant l'arrivée de chaque message, pas en lisant le corps à la fin, parce que seul le moment de l'arrivée distingue un flux d'un lot. Une connexion qui s'ouvre, un code 200 ou 101 et un corps complet à la fermeture ne disent rien du rythme. Quatre mesures couvrent les problèmes de cette leçon.
- Un aller-retour WebSocket : on envoie un message et on mesure le temps avant son écho. Un délai anormal trahit un retard injecté quelque part.
- L'écart entre deux événements SSE : si le producteur émet un événement par seconde, les écarts mesurés doivent rester proches de cette seconde. Des écarts de dizaines de secondes suivis d'une rafale signalent un tampon.
- Le premier battement : il doit arriver en quelques secondes, pas en milliers.
- La panne : on arrête la source, et le flux doit signaler un événement de panne puis se fermer, au lieu de pendre.
Chacune de ces mesures échoue pour une raison précise, ce qui rend le diagnostic lisible. Un écho qui revient mais tard n'a pas la même cause qu'un écho qui ne revient jamais. Des événements qui arrivent tous, mais en bloc, accusent le tampon et non le réseau.
Un mot sur la lecture des résultats. Une mesure qui passe une fois ne prouve pas la robustesse : un flux peut tenir cinq secondes et tomber à la soixantième. Pour juger une borne d'inactivité, il faut donc laisser le flux silencieux plus longtemps que la borne, et regarder s'il survit. C'est la contre-épreuve de la règle de la borne et du battement.
Mettre en pratique
Section intitulée « Mettre en pratique »Le lab fournit un service de notifications qui expose un WebSocket et un flux SSE alimenté par un producteur qui émet une notification par seconde. Sa configuration porte quatre erreurs à la fois : un écho retardé, des événements retenus en tampon, un battement qui ne se déclenche jamais en pratique, et une panne du producteur que le flux ne signale pas. Vous les corrigez dans un fichier de réglages (nommé politique dans le lab), avec le client de mesure fourni qui chronomètre chaque flux. La validation lance ce client et vérifie que l'écho WebSocket revient en moins d'une seconde, que les événements SSE arrivent un par un (au moins deux en quatre secondes, avec moins de 2,5 secondes d'écart entre deux), qu'un premier battement arrive avant quatre secondes dans une fenêtre d'observation de cinq secondes, et qu'un événement de panne et un événement de fermeture sont émis quand le producteur est arrêté.
Le lab ne mesure pas la durée exacte d'une borne d'inactivité, ni les directives d'un proxy précis : ces points restent portés par les pages d'outil.
À retenir
Section intitulée « À retenir »- Un flux long est une connexion qui reste ouverte avec des données par à-coups ; un point d'entrée réglé pour des pages le traite en suspect.
- Un délai de lecture est une borne d'inactivité : elle repart à chaque octet reçu et ne limite pas la durée totale.
- Après une réponse 101, la connexion devient un tunnel ; dans HAProxy, il relève d'une borne distincte de la lecture, et chaque outil a ses propres réglages.
- Un tampon ne perd aucun événement SSE mais détruit leur rythme : le flux devient un lot.
- WebSocket exige qu'on transmette la poignée de main, SSE qu'on ne retienne rien, gRPC qu'on parle HTTP/2 jusqu'au backend.
- Une borne d'inactivité se règle en face du battement de l'application, pas en face de la durée du flux ; mais un battement ne protège pas d'une borne de durée totale, mesurée sur Traefik 3.7.15.
- Un flux silencieux ne se distingue d'un flux mort que par un battement et un signalement explicite de la panne, deux choses qui relèvent du service.
- Un flux se prouve en chronométrant chaque message, jamais en lisant un corps final.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Ces questions vérifient que vous savez expliquer une coupure de flux, choisir une borne et décider de la mesure qui prouve un flux.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.
Points faibles
Aucun sujet sous le seuil de réussite.
À faire ensuite
Des indices pour retenter votre chance ?
Continuer le cours : Équilibrer et vérifier la santé d'un service
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications