Exemple de contention révélée uniquement par un test de charge : la saturation du réseau backend
Résumé de l'article
- Le test de charge met en évidence une contention réseau backend invisible en conditions nominales.
- L’architecture testée repose sur plusieurs frontaux et des backends MySQL / Redis en master-slave.
- La saturation apparaît dès le troisième palier de charge, avant toute limite CPU.
- Redis génère un trafic interne largement supérieur au trafic réellement servi aux utilisateurs.
- L’application lit jusqu’à trois fois plus de données que nécessaire pour produire une page.
- Ce cas illustre l’importance des tests de charge et de la sobriété applicative sur les architectures distribuées.
Dans notre retour sur expérience, l’architecture testée est composée de trois frontaux et de deux serveurs backend. Les serveurs backend fournissent un service MySQL master/slave, c’est-à-dire qu’il n’y a qu’un serveur actif à la fois et un service de cache Redis qui fonctionne également en master/slave.
Sur les deux backends, le premier est master pour MySQL et slave pour Redis, le second est slave pour MySQL et master pour Redis. Ainsi, les flux réseaux provenant des frontaux sont distribués sur les deux backends.
Architecture testée : frontaux multiples et backends MySQL / Redis
Méthodologie du test de charge avec JMeter
Le test de charge a été effectué avec JMeter et le nombre de threads augmente de 25 toutes les 10 minutes :
L’utilisation des paliers permet de voir la correspondance avec les métriques côté serveurs. Si tout était idéal, on retrouverait un escalier avec des paliers de 10 minutes sur les graphes des serveurs.
Premiers signe de contention côté frontaux
Voici la consommation CPU d’un frontal qu’on peut superposer à la courbe de JMeter, tout du moins au début. On voit que les CPU démarrent par des marches d’escalier, mais au bout du troisième palier, après 30 minutes, la CPU ne suit plus les marches.
C’est typique d’une contention qui apparaît au-delà du troisième palier, donc entre 50 et 75 threads au niveau de JMeter.
Analyse des flux réseaux sur les frontaux
On voit que les frontaux reçoivent beaucoup plus de données qu’ils n’en délivrent. Dans la partie verte se trouvent les réponses, c’est-à-dire les pages émises vers les navigateurs et les requêtes faites sur la base de données MySQL et Redis. En bleu, on trouve les requêtes des navigateurs reçues par les frontaux, mais surtout les réponses des backends.
Que se passe-t-il du côté des backends ?
Trafic réseau côté serveur My SQL
Le serveur MySQL reçoit plus de trafic qu’il n’en délivre ! C’est probablement la réplication Redis qui est la source de ce trafic entrant.
Trafic réseaux côté serveur redis
Le serveur Redis émet énormément de trafic vers l’extérieur
Identification de la saturation réseau
Pourquoi le débit plafonne à 450 Mbps au lieu de 1 Gbps ?
Dans ce trafic émis, il y a la réplication Redis pour une part mais aussi les informations qui permettent à l’application de créer les pages.
Et surtout on note l‘écrêtage du débit au troisième palier avec un flux de 450 Mbps !
Pourquoi atteint on une limite à 450 Mbps alors qu’en théorie on devrait passer du 1000 Mbps ?
Parce qu’en pratique, il y a 4 machines qui conversent avec ce serveur, et elles font énormément de requêtes. Donc on se trouve loin des conditions optimales de débit.
Déséquilibre entre trafic applicatif et trafic utilisateur
On voit dans le graphes des frontaux que le trafic émis est de l’ordre de 30 Mbps. Donc le site a un débit de moins de 100 Mbps. Alors que le trafic émis par Redis dépasse les 375 Mbps. Il faut trois fois plus d’informations pour construire une page que ce qu’elle ne contient !
Redis comme accélérateur et facteur de surcharge réseau
On constate pour cette application une surutilisation de Redis. Rien d’étonnant, puisque le Redis stocke les données prêtes à être exploitées par l’application. Les résultats sont pré machés dans Redis et renvoyés directement depuis la mémoire, ce qui accroît les performances. En un peu plus d’une dizaine d’années, le codage des applications passe de l’exécution de requêtes SQL à la lecture des données dans Redis.
Redis utilisé comme mémoire partagée : avantages et limites
En pratique, on utilise Redis comme de la RAM, c’est-à-dire de la mémoire locale. Sauf que quand on a plusieurs frontaux, cette mémoire est partagée. Le bon côté c’est que ça évite de charger des données en cache pour chaque frontal. Le mauvais côté, c’est qu’on accède à cette mémoire à travers le réseau, qui n’a pas du tout les mêmes performances que la RAM.
A noter qu’au bout du troisième palier on sature le réseau, il était donc inutile de faire 8 paliers pendant 1h30 lors de ce test de charge !
Ce type de contention réseau au niveau des backends est assez courante sur les grosses infrastructures qui multiplient les frontaux et les VM ou services.
Perspectives d’amélioration et enjeux d’optimisation applicative
Les perspectives d’amélioration passent par une modification d’architecture, comme utiliser le Redis avec une réplication master/master ou des lectures sur le slave pour alléger le master. Mais surtout, l’application n’est certainement pas optimisée puisqu’elle nécessite pour pour produire ses pages, la lecture de 3 fois plus de données. Il y a donc très certainement un gâchis de lecture de tableaux dont on ne conserve que quelques informations. La démarche de préservation des ressources prend toute son importance sur les sites à forte audience
L'équipe toHero
FAQ - tests de charge, contention réseau et sur utilisation de Redis
Qu'est-ce qu'un test de charge et à quoi sert-il réellement ?
Un test de charge consiste à simuler une montée progressive du nombre d’utilisateurs afin d’observer le comportement réel d’une application sous contrainte. Il permet d’identifier des limites invisibles en environnement nominal, notamment les contentions CPU, mémoire ou réseau, impossibles à détecter sans mise sous pression contrôlée..
Qu'est-ce qu'une contention réseau backend ?
Une contention réseau backend survient lorsque les échanges entre services internes (frontaux, bases de données, cache) saturent la capacité réseau disponible. Le problème ne vient pas du trafic utilisateur, mais des communications internes nécessaires à la construction des pages.
Pourquoi la saturation réseau apparait-elle avant la saturation CPU ?
Parce que dans les architectures modernes, la donnée circule beaucoup plus que le calcul. Dans le cas décrit, Redis est massivement sollicité pour fournir des données pré-calculées, ce qui génère un trafic réseau très élevé avant même que les CPU ne soient saturés.
Comment Redis devient un goulet d'étranglement dans une architecture multi-frontaux ?
Redis devient un goulet d’étranglement lorsqu’il est utilisé comme une mémoire partagée entre plusieurs frontaux. Chaque accès Redis transite par le réseau, contrairement à une lecture en RAM locale. Lorsque l’application effectue un grand nombre de lectures Redis pour construire ses pages, le volume d’échanges internes augmente fortement et peut saturer le réseau backend avant même que les CPU ou la base de données ne soient sollicités.
Pourquoi le trafic redis peut-il être bien supérieur au trafic réellement servi aux utilisateurs ?
Parce que Redis stocke des données intermédiaires prêtes à être exploitées par l’application, souvent plus volumineuses que le contenu final affiché. Dans le cas présenté, l’application lit jusqu’à trois fois plus de données que nécessaire pour produire une page. Ce surcroît de lectures génère un trafic interne massif, sans bénéfice direct pour l’utilisateur final.
Que révèle ce type de test de charge sur la qualité de l'architecture applicative ?
Il met en évidence une inadéquation entre l’architecture technique et les usages applicatifs réels. Une infrastructure peut être dimensionnée correctement, mais rester inefficace si l’application consomme inutilement des ressources. Ce type de test de charge révèle que la performance ne dépend pas uniquement de l’infrastructure, mais surtout de la sobriété des échanges et de l’optimisation applicative.