Le test de saturation a un problème de crédibilité. Les équipes le lancent, obtiennent un rapport impeccable, livrent le build, puis voient une fuite de mémoire apparaître en production trois jours plus tard. Le run n’était pas défectueux. Il a mesuré ce qu’il était configuré pour mesurer. Le problème, c’est que la plupart des configurations de saturation répondent à une question plus étroite que ne le croient les ingénieurs, ce qui explique pourquoi des runs réussis et une production qui fuit continuent de coexister.
Cet article explique pourquoi cela se produit et comment concevoir un run qui l’évitera. Si vous utilisez déjà le test de saturation dans votre pipeline et livrez encore des fuites, la solution n’est presque jamais un run nocturne plus long. La solution est un test d’une autre forme, et elle s’inscrit dans une pratique de test de performance plus large qui traite la trajectoire, et non la durée, comme critère de réussite. Des données récentes du secteur rendent l’enjeu concret : l’enquête de New Relic a chiffré le coût médian d’un arrêt opérationnel à 33 333 dollars par minute, avec une facture annuelle médiane de 76 millions de dollars liée aux pannes. Une seule fuite qui apparaît le troisième jour est un événement qui pèse sur le compte de résultat.
Pourquoi des tests de saturation réussis fuient malgré tout
L’écart entre un tableau de bord au vert et un incident en production remonte presque toujours à l’une de deux erreurs. Soit le test ne peut pas voir la fuite parce qu’il ne regarde pas la bonne métrique, soit il ne peut pas la voir parce qu’il n’a jamais déclenché le chemin de code qui fuit en premier lieu.
La plupart des guides répondent à cela en prescrivant une durée. Huit heures, douze, soixante-douze sur un week-end. C’est cette prescription qui envoie les fuites en production. Une fuite dont le temps de doublement est de 40 heures paraît plate pendant les 8 premières heures, légèrement intéressante à 20 et terrifiante à 60. Un test qui se termine à la 8e heure avec une courbe d’allure linéaire n’est pas la preuve d’un système sain. C’est la preuve que vous avez cessé de regarder trop tôt. Le rapport State of Resilience 2025 de Cockroach Labs a interrogé 1 000 cadres dirigeants de la technologie et a constaté que les organisations subissaient en moyenne 86 pannes par an, 70 % des grandes entreprises mettant 60 minutes ou plus à résoudre chacune d’elles. La plupart de ces incidents étaient évitables au banc d’essai.
La trajectoire plutôt que la durée
Le cadrage est modeste, mais tout change quand on l’accepte. Un test de saturation ne réussit ni n’échoue selon la valeur finale d’une métrique. Il réussit ou échoue selon la pente. Si votre tas (heap) se termine à 2,1 Go après avoir démarré à 2,0 Go, la question intéressante n’est pas l’écart. La question intéressante est de savoir si la pente du plancher post-ramasse-miettes est statistiquement distinguable de zéro sur les derniers 60 % du run.
Ce cadrage change ce que vous construisez. Vous cessez de demander « combien de temps le run doit-il durer » et commencez à demander « quelle est la plus petite croissance horaire que je dois détecter, et quelle durée de run me donne la sensibilité pour la détecter au-dessus du bruit ». Vous cessez de demander « le graphique avait-il l’air plat » et commencez à ajuster des régressions. Vous cessez de vous fier à un seul tableau de bord et commencez à corréler le tas, la durée des pauses du ramasse-miettes (GC), le niveau maximal atteint par le pool de connexions et le nombre de descripteurs de fichiers sur le même axe temporel.
Tout ce qui suit est une manière concrète dont le cadrage par trajectoire se manifeste. Quatre angles morts, quatre métriques, quatre choix de conception.
Les quatre angles morts
La plupart des runs courts et uniformes ratent les fuites pour l’une de quatre raisons structurelles. Chacune a une signature diagnostique, et chacune a une solution qui ne consiste pas à allonger le run pour le principe.
Trop court pour le temps de doublement
Une fuite qui double toutes les 36 heures est invisible dans une fenêtre de 8 heures. La courbe est dans sa zone plate de début d’exponentielle. À la 40e heure en production, c’est un mur. C’est la raison la plus fréquente pour laquelle le test de saturation dans le test logiciel rate ce qu’il a été conçu pour attraper.
Le signal que vous voulez vraiment n’est pas le tas brut. Le tas brut oscille à chaque cycle d’allocation et de ramassage. Le signal, c’est le plancher du tas après GC, échantillonné toutes les 5 minutes, avec une régression linéaire ajustée sur les derniers 60 % du run. Si la pente est supérieure à zéro à p < 0,05, vous avez une fuite, quelle que soit la modestie apparente du chiffre absolu.
La solution de conception consiste à fixer la durée de votre run selon la sensibilité plutôt que la convention. Décidez de la plus petite croissance horaire du tas qui aurait de l’importance en production, puis calculez la durée minimale de run qui vous permet de distinguer cette pente de la gigue du GC. Si vous ne pouvez pas distinguer 2 Mo par heure du bruit dans votre fenêtre actuelle, votre fenêtre est trop courte, et fixer le graphique du regard n’y changera rien.
Charge plate : le trafic réel a une forme
Le trafic de production a des pics et des creux. Les heures creuses sont le moment où le ramasse-miettes devient agressif, où les pools de connexions se vident, où l’éviction du cache s’enclenche et déclenche tous les écouteurs qui y sont rattachés. Les fuites qui se cachent derrière la pression du GC au pic sont exposées au creux. Les fuites qui ne se déclenchent qu’à l’éviction du cache n’allouent jamais rien sous une charge plate de 100 VU, car le cache reste chaud et rien n’est jamais évincé.
Une charge uniforme masque aussi la métrique que vous devriez surveiller de plus près : la durée et la fréquence des pauses du GC le long de la courbe de charge, et non la moyenne sur l’ensemble du run. Ce que vous cherchez, c’est une dérive de la durée des pauses corrélée aux transitions de forme de la charge. Les moyennes masquent la dérive ; les transitions l’exposent.
La solution consiste à modeler la saturation pour qu’elle épouse votre véritable courbe de trafic. Montez en charge, maintenez le pic pendant deux heures, redescendez à 20 % pendant 90 minutes, remontez. Répétez le cycle tout au long du run. Si votre production connaît une heure calme chaque nuit, mettez une heure calme dans le test. Une ligne plate sur le générateur de charge est un test de charge aux ambitions de saturation, pas une vraie saturation.
La tâche planifiée que vous avez oublié d’exécuter
Les chemins de code les plus susceptibles de fuir sont ceux qui s’exécutent rarement : tâches cron, réconciliation de minuit, génération de rapports hebdomadaires, rééquilibrage Kafka horaire, nettoyage (vacuum) nocturne de la base de données. Ils sont moins souvent relus, ils allouent de grandes structures transitoires et conservent des références plus longtemps qu’ils ne le devraient. Et ils n’apparaissent presque jamais dans le scénario de saturation, qui ne couvre généralement que le flux des requêtes HTTP.
Ici, les métriques à superposer à la chronologie sont des fonctions en escalier plutôt que des pentes :
- Le niveau maximal atteint par le pool de connexions, échantillonné autour de chaque exécution de tâche planifiée.
- Le nombre de descripteurs de fichiers avant, pendant et après la tâche.
- Le nombre de threads si la tâche engendre des workers.
- Toute profondeur de file d’attente que la tâche produit ou consomme.
Si l’une de ces valeurs grimpe d’un cran à chaque exécution de la tâche sans jamais redescendre, vous avez trouvé une fuite que le run centré sur le seul trafic ne révélerait jamais.
La solution de conception est un changement de définition. Votre scénario n’est pas « le trafic ». C’est « le trafic plus le calendrier ». Énumérez chaque tâche planifiée qui se déclencherait au cours d’une semaine de production et, soit compressez son calendrier dans la fenêtre de test, soit déclenchez-la explicitement à des intervalles réalistes. Un run qui n’exécute jamais un cycle complet de votre tâche planifiée la plus lente est un run de charge aux ambitions de saturation.
Discordance de politique de redémarrage
C’est la plus subtile et celle que l’on rate le plus souvent. Les environnements de test sont recyclés de manière agressive. La CI démarre un conteneur neuf à chaque run. L’orchestrateur tue tout ce qui présente un pic de 5xx. Les seuils des contrôles de santé sont réglés au plus serré pour un retour rapide. La production, en revanche, peut tourner 30 jours entre deux redémarrages. Une fuite qui mettrait 200 heures à devenir importante n’a jamais l’occasion de le devenir dans un test qui se réinitialise à la 12e heure parce qu’un contrôle de santé a vacillé.
La métrique à surveiller est triviale : la durée de fonctionnement du conteneur ou du processus, en regard de la métrique de fuite. Tout redémarrage pendant le run invalide la trajectoire à partir de ce point. Pourtant, dans la plupart des configurations de CI, cette corrélation n’est jamais tracée, et le run est marqué au vert parce que les métriques après le redémarrage se sont trouvées correctes.
La solution consiste à aligner la politique de redémarrage de la production dans l’environnement de test, pas celle de la CI. Élargissez les seuils de vivacité (liveness). Désactivez l’arrêt agressif par contrôle de santé pendant toute la durée du run. Traitez tout redémarrage en cours de run comme un test de saturation échoué, nécessitant investigation et relance, plutôt que comme un incident que vous contournez au tableau de bord. Si votre orchestrateur tolérerait un processus de 30 jours en production, votre banc d’essai devrait en tolérer un pendant toute la durée du run.
À quoi ressemble un vrai test de saturation
Utilisez ceci comme liste de contrôle pour votre prochain run. Si votre pipeline actuel échoue sur plus de trois de ces points, le chiffre de huit heures n’est pas votre problème.
- La durée du run est fixée par la sensibilité de détection visée, calculée à partir de la croissance horaire acceptable, et non par « une nuit ».
- La courbe de charge est modelée pour refléter la production, avec pics, creux et transitions, plutôt qu’un plateau plat.
- Chaque tâche planifiée qui se déclencherait au cours d’une semaine de production est soit compressée dans la fenêtre du run, soit déclenchée explicitement.
- La politique de redémarrage et de vivacité de l’environnement de test correspond à la production, et non aux valeurs par défaut de la CI.
- Le plancher du tas après GC est le signal de tas principal, et non le tas brut, et il est ajusté par une régression linéaire sur les derniers 60 % du run.
- Le niveau maximal du pool de connexions, le nombre de descripteurs de fichiers et le nombre de threads sont tracés comme des séries temporelles sur le même axe que la charge et le calendrier des tâches.
- La durée des pauses du GC est suivie le long de la courbe de charge, et non résumée en une moyenne sur l’ensemble du run.
- Tout redémarrage de processus en cours de run invalide automatiquement le run et exige une investigation avant de pouvoir être marqué au vert.
- Le critère de réussite est écrit sous la forme d’un seuil de pente et d’un plafond de niveau maximal, et non comme « le graphique avait l’air plat ».
Ratez un seul de ces points, et vous aurez construit un run capable de produire un faux vert. Obtenez les neuf, et les runs qui réussissent voudront dire quelque chose.
Où la saturation s’inscrit par rapport au reste
Le test sous charge soutenue répond à une seule question : ce qui s’accumule au fil du temps. Il ne remplace pas les autres disciplines de performance, et il en dépend. Le test de charge vous dit si le système tient le débit de pointe ; sans cette référence, une saturation modelée n’a aucune charge cible à maintenir. Le comportement en rafale est une tout autre question, et si vous n’avez pas soumis le système à un trafic soudain, vous livrez à l’aveugle à chaque lancement marketing, événement viral et ruée de connexions du lundi matin.
Les architectures distribuées ajoutent leur propre dimension. Un monolithe fuit dans un seul processus ; un maillage de services peut fuir dans la façon dont les services se parlent entre eux, et la trace doit suivre la requête à travers chaque saut. Exécuter des runs sous charge soutenue à travers des microservices avec corrélation de traces distribuées est une discipline différente de la saturation d’un service unique, et cela mérite sa propre conception de scénario. Il en va de même une couche plus bas, au niveau de l’interface : les goulets d’étranglement au niveau de l’API qui apparaissent sous charge soutenue amplifient chaque mode de défaillance des quatre angles morts ci-dessus, car un contrat lent aggrave chaque fuite que la charge de travail déclenche.
Concevoir pour la sensibilité de détection
Le chiffre de huit heures est un doudou rassurant. Ce qui compte, c’est de savoir si votre run peut voir la pente dans les métriques qui fuient : plancher du tas après GC, profondeur du pool, nombre de descripteurs de fichiers, durée des pauses du GC, à travers des formes de charge et des tâches planifiées qui reflètent ce que la production fait réellement. Concevez pour la sensibilité de détection. Si votre dernier run a réussi et que la production a quand même fui, le prochain n’a pas besoin d’être plus long. Il doit regarder la bonne chose, sous la bonne forme, avec la bonne politique de redémarrage. Lorsque vous serez prêt à en construire un qui attrape vraiment la fuite, contactez-nous, et nous le concevrons avec vous.
FAQ
Combien de temps un test de saturation doit-il durer ?
Assez longtemps pour distinguer la plus petite croissance horaire de ressources qui aurait de l’importance en production de la gigue du ramasse-miettes. Si une pente de tas de 2 Mo par heure ferait tomber votre service en une semaine de fonctionnement, votre run doit être assez long pour détecter cette pente au-dessus du bruit avec une régression linéaire sur le plancher post-GC. C’est généralement plus long que 8 heures et souvent plus court que 72.
Quelle est la différence entre le test de saturation et le test d’endurance ?
Ce sont la même pratique sous deux noms. Certaines équipes et certains prestataires préfèrent « endurance », d’autres préfèrent « saturation » ; le désaccord est régional et stylistique, pas technique. Les deux désignent une charge soutenue sur une période prolongée, en surveillant l’accumulation.
Pourquoi mon test de saturation a-t-il réussi alors que la production avait une fuite de mémoire ?
Presque toujours pour l’une de quatre raisons : le run était plus court que le temps de doublement de la fuite, la charge était plate alors que la production a une forme journalière, le run n’a jamais exécuté une tâche planifiée qui fuit, ou l’environnement de test a redémarré un processus que l’orchestrateur aurait maintenu en vie en production. Corrigez la conception, pas la durée.
Découvrez comment QAwerk a maintenu la stabilité de 8 portails riches en contenu sous un trafic soutenu de 110 millions d’étudiants par an, avant que Keystone ne passe à une plus grande échelle.