Résolution des problèmes de latence élevée : Diagnostic des problèmes de connexion MongoDB
Lorsque votre application MongoDB semble lente malgré des requêtes individuelles rapides, une latence élevée en est la cause. Ce guide complet explore le diagnostic et la résolution des goulots d'étranglement de performance liés aux connexions. Apprenez à résoudre les problèmes réseau, à optimiser les configurations de pooling de connexions et à identifier la contention des ressources serveur (CPU, mémoire, E/S) qui impacte la réactivité globale. Des conseils pratiques et des stratégies de surveillance vous aident à identifier la cause exacte de vos problèmes de latence.
Résolution des problèmes de latence élevée : Diagnostic des problèmes de connexion MongoDB
Une latence élevée de MongoDB n'est pas toujours un problème de requête lente. Parfois, la requête est rapide une fois qu'elle atteint le serveur, mais la demande attend une connexion, bute sur le DNS, traverse un chemin réseau lent, retente après un échec transitoire, ou passe trop de temps à transférer un grand ensemble de résultats vers l'application.
La première tâche consiste à diviser la latence de bout en bout en plusieurs parties. Le temps d'exécution côté serveur, le temps d'extraction de connexion, l'aller-retour réseau, le transfert des résultats et le traitement applicatif sont des problèmes différents avec des solutions différentes.
1. Configuration réseau et connectivité
Les problèmes réseau sont une source fréquente de latence inattendue. Même une perte de paquets mineure ou une augmentation des temps d'aller-retour (RTT) entre vos serveurs d'application et vos instances MongoDB peut avoir un impact significatif sur les performances.
1.1. Latence entre l'application et les serveurs MongoDB
Ping et Traceroute : Utilisez des outils de diagnostic réseau standard pour mesurer le RTT et identifier les goulots d'étranglement potentiels dans le chemin réseau.
ping <hôte_mongodb> traceroute <hôte_mongodb> # ou tracert sur Windows- Astuce : Des temps de ping constamment élevés ou des variations importantes peuvent indiquer une instabilité réseau.
Règles de pare-feu et congestion réseau : Assurez-vous qu'aucun pare-feu n'introduit de délais (par exemple, via une inspection approfondie des paquets) ou que les liaisons réseau ne sont pas saturées. Surveillez le trafic réseau entre vos couches applicative et base de données.
1.2. Délais de résolution DNS
Des recherches DNS lentes peuvent ajouter de la latence à chaque tentative de connexion si des noms d'hôte sont utilisés au lieu d'adresses IP. Assurez-vous que vos serveurs DNS sont réactifs et correctement configurés.
2. Problèmes de pooling de connexions
Le pooling de connexions est essentiel pour les performances, mais des configurations incorrectes ou une utilisation excessive peuvent entraîner une latence significative.
2.1. Comprendre le pooling de connexions
Le pooling de connexions maintient un ensemble de connexions de base de données ouvertes que les applications peuvent réutiliser, évitant ainsi les frais généraux liés à l'établissement d'une nouvelle connexion pour chaque requête. Cela réduit considérablement le temps de configuration de la connexion.
2.2. Nombre maximum de connexions insuffisant
Si la taille maximale du pool de connexions de votre application est trop faible, vos threads d'application peuvent devoir attendre une connexion disponible, ce qui entraîne une mise en file d'attente des requêtes et une latence élevée. À l'inverse, un pool excessivement grand peut submerger le serveur MongoDB.
Surveillance : La plupart des pilotes MongoDB fournissent des statistiques sur l'utilisation du pool de connexions. Recherchez des métriques comme :
pool.size: Nombre actuel de connexions dans le pool.pool.in_use: Nombre de connexions actuellement utilisées.pool.waiters: Nombre de threads en attente d'une connexion.
Si
pool.waitersest constamment élevé, votremaxPoolSizeest peut-être trop petit.Configuration (Exemple - Python/PyMongo) :
from pymongo import MongoClient client = MongoClient( 'mongodb://localhost:27017/', maxPoolSize=20, # Ajustez cette valeur en fonction de vos besoins minPoolSize=5 )- Astuce : Le
maxPoolSizeoptimal dépend de la concurrence de votre application, du nombre de cœurs du serveur MongoDB et de la latence réseau. Commencez par une valeur modérée et ajustez-la en fonction de la surveillance.
- Astuce : Le
2.3. Latence d'établissement de la connexion
Même avec le pooling, l'établissement initial d'une connexion peut prendre du temps, en particulier sur des réseaux à latence élevée ou si une négociation TLS/SSL est impliquée. Cette latence est encourue lorsque le pool doit créer une nouvelle connexion parce que toutes les connexions existantes sont utilisées ou ont expiré.
- Surcharge TLS/SSL : Bien que crucial pour la sécurité, la négociation TLS/SSL ajoute une surcharge. Assurez-vous que votre matériel est capable de gérer la charge de chiffrement/déchiffrement.
3. Contention des ressources du serveur MongoDB
Lorsque le serveur MongoDB lui-même est sous pression, cela peut entraîner une latence accrue, même pour des opérations simples.
3.1. Utilisation du CPU
Une utilisation élevée du CPU sur le serveur MongoDB peut ralentir toutes les opérations, y compris la gestion des connexions et le traitement des requêtes. Cela peut être causé par :
Requêtes inefficaces : Des requêtes qui effectuent des analyses complètes de collection ou des agrégations complexes.
Concurrence élevée : Trop de requêtes simultanées submergeant la puissance de traitement du serveur.
Opérations en arrière-plan : Tâches de maintenance, élections ou synchronisation de données.
Surveillance : Utilisez
mongostatou les outils de surveillance de votre fournisseur cloud pour vérifier l'utilisation du CPU.mongostat --host <hôte_mongodb> --port 27017Recherchez des valeurs élevées de
qr(longueur de la file d'attente des requêtes) etqw(longueur de la file d'attente des écritures).
3.2. Utilisation de la mémoire et pagination
MongoDB fonctionne mieux lorsque son ensemble de travail (les données et les index activement utilisés) tient dans la RAM. Si le serveur commence à paginer sur le disque en raison d'une RAM insuffisante, les performances se dégraderont considérablement.
Surveillance : Surveillez l'utilisation de la RAM et l'activité de pagination sur le serveur MongoDB.
# Sous Linux, utilisez top ou htop topSi vous voyez une utilisation significative de la pagination (
Swapdanstop), c'est un indicateur fort d'une pression mémoire.Solution : Augmentez la RAM du serveur ou optimisez votre déploiement MongoDB pour réduire l'empreinte mémoire (par exemple, en vous assurant que les index couvrent vos requêtes).
3.3. Goulots d'étranglement des E/S disque
Des E/S disque lentes sont un goulot d'étranglement courant, surtout si les données ou les index ne sont pas entièrement mis en cache en mémoire.
Surveillance : Utilisez
iostatsur les systèmes Linux pour vérifier l'utilisation du disque.iostat -xz 5Des valeurs élevées de
%util,awaitousvctmindiquent une saturation du disque.Solution : Utilisez un stockage plus rapide (SSD), assurez-vous d'avoir suffisamment de RAM pour la mise en cache et optimisez les requêtes pour réduire les lectures disque.
3.4. Débit réseau sur le serveur
Même si le chemin réseau est bon, l'interface réseau du serveur MongoDB peut être saturée s'il gère un volume massif de requêtes.
- Surveillance : Surveillez le trafic réseau sur le serveur MongoDB lui-même.
4. Considérations au niveau de l'application
Parfois, le problème ne vient pas directement de MongoDB ou du réseau, mais de la manière dont l'application interagit avec la base de données.
4.1. Appels de pilote excessifs
Une application effectuant un très grand nombre d'appels de base de données petits et indépendants au lieu de regrouper les opérations peut entraîner une surcharge de connexion et une latence accrue.
- Exemple : Effectuer des opérations
insert_oneindividuelles dans une boucle plutôt que d'utiliserinsert_many.
4.2. Opérations de longue durée dans l'application
Si votre application effectue des calculs ou des E/S importants après avoir récupéré les données de MongoDB mais avant de renvoyer une réponse, cela apparaîtra comme une latence de bout en bout élevée.
- Solution : Profilez le code de votre application pour identifier et optimiser ces sections lentes.
Un triage de latence étape par étape
Commencez par mesurer la requête en plusieurs parties. Un seul nombre, comme "l'API prend 900 ms", ne suffit pas. Vous voulez savoir combien de temps est passé à attendre une connexion, à envoyer la commande, à exécuter sur MongoDB, à recevoir les résultats et à sérialiser la réponse.
La plupart des pilotes MongoDB exposent des hooks de surveillance des commandes. Ajoutez une journalisation temporaire autour du début de la commande et de son succès ou échec. Incluez le nom de la commande, la durée, la base de données, la collection et un ID de requête. Ne journalisez pas les valeurs complètes des requêtes si elles peuvent contenir des données sensibles.
Si la durée de la commande est faible mais que l'API est lente, MongoDB n'est probablement pas le principal goulot d'étranglement. Examinez le CPU de l'application, les appels HTTP en aval, la sérialisation JSON, le rendu des modèles ou les attentes dans les files d'attente. Si la durée de la commande est élevée mais que le profileur MongoDB montre une exécution rapide, le retard peut provenir de l'extraction de la connexion, du transfert réseau, du DNS, de la négociation TLS ou du décodage des résultats.
Le temps d'extraction de la connexion est particulièrement facile à manquer. Un pool peut être sain au démarrage et saturé lors des pics de trafic. Si les requêtes attendent un socket, chaque requête semble lente du point de vue de l'application, même si MongoDB exécute chaque commande rapidement une fois qu'elle arrive. Suivez le temps d'attente du pool si votre pilote l'expose. Sinon, mesurez le temps autour de l'appel à la base de données et comparez-le avec le temps du profileur côté serveur.
Un test local simple peut cerner le problème :
mongosh "mongodb://mongo1.internal:27017/app" --eval 'db.runCommand({ ping: 1 })'
Exécutez-le depuis votre ordinateur portable, depuis l'hôte de l'application et depuis un autre hôte dans le même sous-réseau si possible. Si seul l'hôte de l'application est lent, suspectez un DNS local, des règles de pare-feu, du routage, des nœuds surchargés ou la mise en réseau des conteneurs. Si chaque hôte est lent, examinez la couche de base de données ou le chemin réseau entre les couches.
Pour le DNS, testez les recherches répétées :
time nslookup mongo1.internal
Une recherche lente lors de la création d'une nouvelle connexion peut nuire aux services qui créent fréquemment des clients au lieu d'en réutiliser un. Dans la plupart des applications, créez un MongoClient par processus et réutilisez-le. Créer un nouveau client par requête est l'un des moyens les plus rapides de générer de la latence.
TLS peut également ajouter un coût, en particulier lors de la création de connexions. Cela ne signifie pas que vous devez désactiver TLS. Cela signifie que vous devez réutiliser les connexions mises en pool, éviter le renouvellement inutile des clients et vous assurer que le CPU n'est pas saturé pendant les négociations.
Sur le serveur, comparez les métriques MongoDB avec les métriques du système d'exploitation. Si mongostat montre des files d'attente qui augmentent et que l'hôte montre un CPU élevé, vous avez peut-être une pression de requêtes ou de concurrence. Si le CPU est modeste mais que iostat montre des temps d'attente élevés, le stockage fait probablement partie du problème. Si la pression mémoire provoque de la pagination, corrigez cela en premier ; un hôte de base de données qui pagine rendra tout aléatoire et lent.
Les grands ensembles de résultats peuvent ressembler à une latence de connexion. Une requête qui renvoie 50 000 documents peut s'exécuter rapidement mais passer du temps à transférer des données sur le réseau et à les décoder dans le pilote. Utilisez des projections, la pagination et des limites côté serveur. Pour les API, renvoyez les champs dont l'écran a réellement besoin, pas le document entier parce que c'était pratique pendant le développement.
Enfin, vérifiez le comportement de la topologie. Pendant les élections de l'ensemble de réplicas, les écritures sont interrompues jusqu'à ce qu'un nouveau primaire soit élu. Les pilotes doivent également découvrir les changements de topologie. Si les pics de latence coïncident avec des élections, des redémarrages de nœuds, des fenêtres de maintenance ou des problèmes réseau, la solution peut être la stabilité et le comportement de basculement plutôt que le réglage des requêtes. Assurez-vous que la chaîne de connexion inclut les membres de l'ensemble de réplicas ou l'enregistrement SRV approprié, et définissez les délais d'attente délibérément pour que l'application échoue de manière prévisible au lieu de se bloquer trop longtemps.
Une note d'incident utile se termine par des preuves : temps d'attente du pool, durée de la commande, durée du profileur, RTT réseau, CPU, mémoire, E/S disque et la forme exacte de la chaîne de connexion avec les secrets supprimés. Cela vous donne un véritable diagnostic au lieu d'une collection de suppositions.
Les paramètres de délai d'attente font partie du diagnostic
Les délais d'attente ne corrigent pas la latence, mais ils décident à quel point la latence est ressentie par les utilisateurs. Si le délai d'attente de sélection du serveur est trop élevé, une application peut se bloquer longtemps après avoir pu renvoyer une erreur contrôlée. Si le délai d'attente du socket est trop bas, des rapports normaux de longue durée peuvent échouer même si la base de données est saine. Définissez-les délibérément pour la charge de travail.
Pour les API de requête-réponse, un délai d'attente de sélection du serveur plus court est souvent logique car l'utilisateur attend. Pour les travaux par lots, un délai d'attente plus long peut être acceptable. Séparez ces clients si le même service fait les deux. Une requête de tableau de bord et une exportation nocturne ne devraient pas toujours partager le même délai d'attente et le même comportement de pool.
Vérifiez également le comportement de nouvelle tentative. Les écritures avec nouvelle tentative et les nouvelles tentatives du pilote peuvent lisser les brèves erreurs réseau, mais elles peuvent également faire en sorte qu'une seule requête utilisateur prenne plus de temps que prévu si chaque tentative attend près du délai d'attente. Journalisez le nombre de nouvelles tentatives lorsque c'est possible. Un service qui réussit après des nouvelles tentatives peut toujours être malsain si chaque requête refait silencieusement des tentatives en arrière-plan.
Dimensionnement du pool de connexions en termes simples
Un pool plus grand n'est pas automatiquement plus rapide. Si la base de données peut traiter confortablement 100 opérations simultanées et que votre application ouvre 1 000 connexions occupées, vous pouvez augmenter le changement de contexte, l'utilisation de la mémoire et la mise en file d'attente. Si le pool est trop petit, les threads de l'application attendent même si MongoDB a de la capacité. La bonne taille de pool provient de la concurrence, de la durée des opérations et de la capacité du serveur.
Commencez par demander combien de requêtes peuvent atteindre la base de données en même temps à partir d'une seule instance d'application. Multipliez ensuite par le nombre d'instances d'application. Un maxPoolSize qui semble modeste dans un processus peut devenir important dans une flotte. Dix pods d'application avec un pool de 100 peuvent créer jusqu'à 1 000 connexions avant de compter les outils d'administration, les travaux et autres services.
Surveillez le renouvellement des connexions. Si les connexions s'ouvrent et se ferment constamment, découvrez pourquoi. Les délais d'inactivité, les équilibreurs de charge, les passerelles NAT, les environnements d'exécution sans serveur et la création de clients par requête peuvent tous provoquer un renouvellement. Les connexions stables mises en pool produisent généralement une latence plus stable.
Une courte liste de contrôle sur le terrain
Lorsque la latence augmente, rassemblez des preuves avant de tout redémarrer :
Application :
- centiles de durée des requêtes
- durée de la commande de base de données
- temps d'attente d'extraction de connexion
- nombre de nouvelles tentatives
- taille du résultat
MongoDB :
- entrées du profileur pour les commandes lentes
- opérations en cours pendant le pic
- retard de réplication
- connexions et lecteurs/rédacteurs en file d'attente
Hôte et réseau :
- saturation du CPU
- pression mémoire et pagination
- attente/utilisation du disque
- perte de paquets et RTT
- temps de recherche DNS
Cette liste de contrôle pointe généralement vers l'un des trois scénarios : l'application attend une connexion, MongoDB est lent à exécuter la commande, ou le réseau/le transfert de résultats est lent autour d'une commande par ailleurs rapide. Chaque scénario a une solution différente.
Une note de clôture pratique
La résolution des problèmes de latence élevée dans les applications MongoDB nécessite une approche systématique. En examinant la connectivité réseau, les configurations du pool de connexions et l'utilisation des ressources du serveur, vous pouvez identifier la cause profonde des retards. N'oubliez pas que la latence est un symptôme, et une vision holistique de votre application et de votre infrastructure de base de données est essentielle pour atteindre des performances optimales.
Commencez par surveiller les coupables les plus courants : le RTT réseau, les waiters du pool de connexions et le CPU/mémoire/E/S disque du serveur. Approfondissez progressivement dans des domaines plus spécifiques si nécessaire. L'examen régulier de ces métriques et configurations aidera à empêcher les problèmes de latence d'affecter vos utilisateurs.