Comment surveiller les performances de MongoDB

L’auteur a sélectionné le Fonds pour l’Internet ouvert / la Liberté d’expression pour recevoir un don dans le cadre du programme Write for Donations.

Introduction

La surveillance est une partie essentielle de l’administration de base de données, car elle vous permet de comprendre les performances et la santé globale de votre base de données. En surveillant les performances de votre base de données, vous pouvez avoir une meilleure idée de sa capacité actuelle, observer comment sa charge de travail évolue avec le temps et planifier à l’avance pour mettre à l’échelle la base de données une fois qu’elle commence à approcher ses limites. Cela peut également vous aider à remarquer des problèmes matériels sous-jacents ou un comportement anormal comme une augmentation inattendue de l’utilisation de la base de données. Enfin, la surveillance peut aider à diagnostiquer les problèmes avec les applications utilisant la base de données, comme les requêtes d’application qui provoquent des goulots d’étranglement.

MongoDB est livré avec une variété d’outils et d’utilitaires que vous pouvez utiliser pour observer les performances de votre base de données. Dans ce tutoriel, vous apprendrez comment surveiller les métriques de base de données à la demande en utilisant des commandes et des outils intégrés. Vous vous familiariserez également avec le profileur de base de données de MongoDB qui peut vous aider à détecter les requêtes mal optimisées.

Prérequis

Pour suivre ce tutoriel, vous aurez besoin de :

Note : Les tutoriels liés sur la configuration de votre serveur, l’installation de MongoDB et la sécurisation de l’installation de MongoDB font référence à Ubuntu 20.04. Ce tutoriel se concentre sur MongoDB lui-même, pas sur le système d’exploitation sous-jacent. Il fonctionnera généralement avec n’importe quelle installation MongoDB indépendamment du système d’exploitation tant que l’authentification a été activée.

Étape 1 — Préparation des données de test

Pour expliquer comment surveiller les performances de MongoDB, cette étape décrit comment ouvrir l’interpréteur de commandes MongoDB pour se connecter à votre instance MongoDB installée localement et créer une collection d’exemple à l’intérieur.

Pour créer la collection d’échantillons utilisée dans ce guide, connectez-vous à l’interpréteur de commandes MongoDB en tant qu’utilisateur administratif. Ce tutoriel suit les conventions du tutoriel de sécurité MongoDB préalable tutoriel de sécurité MongoDB et suppose que le nom de cet utilisateur administratif est AdminSammy et que sa base de données d’authentification est admin. Assurez-vous de modifier ces détails dans la commande suivante pour refléter votre propre configuration, le cas échéant :

  1. mongo -u AdminSammy -p --authenticationDatabase admin

Entrez le mot de passe défini lors de l’installation pour accéder à l’interpréteur de commandes. Après avoir fourni le mot de passe, vous verrez le signe de l’invite >.

Remarque : Lors d’une connexion fraîche, l’interpréteur de commandes MongoDB se connectera à la base de données test par défaut. Vous pouvez utiliser cette base de données en toute sécurité pour expérimenter avec MongoDB et l’interpréteur de commandes MongoDB.

Alternativement, vous pourriez passer à une autre base de données pour exécuter toutes les commandes d’exemple données dans ce tutoriel. Pour passer à une autre base de données, exécutez la commande use suivie du nom de votre base de données :

  1. use database_name

La surveillance de la base de données n’est pas très pratique ou utile lors de la manipulation d’un petit ensemble de données, car le système de base de données n’aura besoin de scanner que quelques enregistrements pour une requête donnée. Pour illustrer les fonctionnalités de surveillance des performances de MongoDB, vous aurez besoin d’une base de données avec suffisamment de données pour que MongoDB mette un temps significatif à exécuter les requêtes.

À cette fin, les exemples tout au long de ce guide font référence à une collection d’échantillons nommée accounts contenant un grand nombre de documents. Chaque document représente un compte bancaire individuel avec un solde de compte généré de manière aléatoire. Chaque document dans la collection aura une structure comme ceci :

An example bank account document
{
    "number": "1000-987321",
    "currency": "USD",
    "balance": 431233431
}

Ce document exemple contient les informations suivantes :

  • number : Ce champ représente le numéro de compte pour le compte donné. Dans cette collection, chaque numéro de compte aura un préfixe de 1000- suivi d’un identifiant numérique incrémentiel.
  • currency : Ce champ indique dans quelle devise le solde de chaque compte est stocké. La valeur de currency de chaque compte sera soit USD ou EUR.
  • balance : Ceci montre le solde pour chaque compte bancaire donné. Dans cette base de données exemple, le champ balance de chaque document aura une valeur générée de manière aléatoire.

Au lieu d’insérer manuellement un grand nombre de documents, vous pouvez exécuter le code JavaScript suivant pour créer simultanément une collection nommée accounts et y insérer un million de tels documents :

  1. for (let i = 1; i <= 1000000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "1000-" + i,
  4. "currency": i > 500000 ? "USD" : "EUR",
  5. "balance": Math.random() * 100000
  6. })
  7. }

Ce code exécute une boucle for qui s’exécute un million de fois d’affilée. À chaque itération de la boucle, il exécute une méthode insertOne() sur la collection des comptes pour insérer un nouveau document. À chaque itération, la méthode attribue une valeur au champ number composé du préfixe 1000- avec la valeur contenue dans la valeur i pour cette itération. Cela signifie que la première fois que cette boucle s’itérera, la valeur du champ number sera définie sur 1000-1; la dernière fois qu’elle s’itérera, elle sera définie sur 1000-1000000.

La devise est toujours représentée comme USD pour les comptes dont les numéros sont supérieurs à 500000 et comme EUR pour les comptes dont les numéros sont inférieurs à cela. Le champ de solde utilise la fonction Math.random() pour générer un nombre aléatoire entre 0 et 1, puis multiplie le nombre aléatoire par 100000 pour fournir des valeurs plus grandes.

Remarque : L’exécution de cette boucle peut prendre un certain temps, même au-delà de 10 minutes. Il est prudent de laisser l’opération s’exécuter jusqu’à ce qu’elle se termine.

La sortie vous informera du succès et renverra l’ ObjectId du dernier document qui a été inséré :

Output
{ "acknowledged" : true, "insertedId" : ObjectId("61a38a4beedf737ac8e54e82") }

Vous pouvez vérifier que les documents ont été correctement insérés en exécutant la méthode count() sans argument, qui récupérera le nombre de documents dans la collection :

  1. db.accounts.count()
Output
1000000

Dans cette étape, vous avez créé avec succès la liste des documents d’exemple qui serviront de données de test dans ce guide pour expliquer les outils que MongoDB fournit pour la surveillance des performances. À l’étape suivante, vous apprendrez à vérifier les statistiques d’utilisation de base du serveur.

Étape 2 — Vérification des statistiques d’utilisation du serveur

MongoDB suit automatiquement un certain nombre de statistiques de performance utiles, et les vérifier régulièrement est un moyen fondamental de surveiller votre base de données. Notez que ces statistiques ne fourniront pas un aperçu en temps réel de ce qui se passe avec votre base de données, mais elles peuvent être utiles pour déterminer comment la base de données fonctionne et s’il existe des problèmes imminents.

Avertissement: Les commandes de surveillance MongoDB décrites dans ce guide renvoient des informations potentiellement sensibles sur votre base de données et ses performances. Pour cette raison, certaines de ces commandes nécessitent des autorisations avancées.

Plus précisément, la méthode serverStatus() décrite dans cette étape ainsi que les commandes mongostat et mongotop mises en évidence dans la prochaine étape nécessitent toutes que les utilisateurs aient été accordés le rôle clusterMonitor pour les exécuter. De même, la méthode setProfilingLevel() décrite dans l’étape 4 nécessite le rôle dbAdmin.

En supposant que vous avez suivi le tutoriel préalable sur Comment sécuriser MongoDB sur Ubuntu 20.04 et que vous êtes connecté à votre instance MongoDB en tant qu’utilisateur administratif que vous avez créé dans ce guide, vous devrez lui accorder ces rôles supplémentaires pour suivre les exemples de ce guide.

Tout d’abord, passez à la base de données d’authentification de votre utilisateur. Cela correspond à admin dans l’exemple suivant, mais connectez-vous à votre propre base de données d’authentification si elle est différente :

  1. use admin
Output
switched to db admin

Ensuite, exécutez une méthode grantRolesToUser() et accordez à votre utilisateur le rôle clusterMonitor ainsi que le rôle dbAdmin sur la base de données où vous avez créé la collection accounts. L’exemple suivant suppose que la collection accounts se trouve dans la base de données test :

  1. db.grantRolesToUser(
  2. "AdminSammy",
  3. [
  4. "clusterMonitor",
  5. { role : "dbAdmin", db : "test" }
  6. ]
  7. )

Veuillez noter qu’il est généralement considéré comme plus sûr d’avoir des profils d’utilisateurs dédiés à des objectifs spécifiques. De cette façon, aucun utilisateur n’aura de privilèges inutilement étendus. Si vous travaillez dans un environnement de production, vous voudrez peut-être avoir un utilisateur dédié dont le seul but est de surveiller la base de données.

L’exemple suivant crée un utilisateur MongoDB nommé MonitorSammy et leur accorde les rôles nécessaires pour que vous puissiez suivre les exemples de ce tutoriel. Notez qu’il inclut également le rôle readWriteAnyDatabase, qui permettra à cet utilisateur de lire et d’écrire des données dans n’importe quelle base de données du cluster :

  1. db.createUser(
  2. {
  3. user: "MonitorSammy",
  4. pwd: passwordPrompt(),
  5. roles: [ { role : "dbAdmin", db : "test" }, "clusterMonitor", "readWriteAnyDatabase" ]
  6. }
  7. )

Après avoir accordé à votre utilisateur les rôles appropriés, revenez à la base de données où se trouve votre collection accounts :

  1. use test
Output
switched to db test

Commencez par vérifier les statistiques globales de la base de données en exécutant la méthode stats() :

  1. db.stats(1024*1024)

L’argument de cette méthode (1024*1024) est le facteur d’échelle et indique à MongoDB de retourner les informations de stockage en mégaoctets. Si vous l’omettez, les valeurs seront toutes présentées en octets.

La méthode stats() renvoie une sortie courte et concise avec quelques statistiques importantes concernant la base de données actuelle :

Output
{ "db" : "test", "collections" : 3, "views" : 0, "objects" : 1000017, "avgObjSize" : 80.8896048767171, "dataSize" : 77.14365005493164, "storageSize" : 24.109375, "indexes" : 4, "indexSize" : 9.9765625, "totalSize" : 34.0859375, "scaleFactor" : 1048576, "fsUsedSize" : 4238.12109375, "fsTotalSize" : 24635.703125, "ok" : 1 }

Cette sortie fournit un aperçu des données que cette instance MongoDB stocke. Les clés suivantes renvoyées dans cette sortie peuvent être particulièrement utiles :

  • La clé objects montre le nombre total de documents dans la base de données. Vous pouvez utiliser cela pour évaluer la taille de la base de données et, lorsqu’elle est observée au fil du temps, sa croissance.
  • avgObjectSize montre la taille moyenne de ces documents, donnant un aperçu de savoir si la base de données fonctionne sur de grands et complexes documents ou de petits. Cette valeur est toujours affichée en octets, quel que soit le facteur d’échelle que vous spécifiez.
  • Les clés collections et indexes indiquent combien de collections et d’index sont actuellement définis dans la base de données.
  • La clé totalSize indique la quantité de stockage que la base de données occupe sur le disque.

Ces informations renvoyées par la méthode stats() peuvent vous aider à avoir une idée de la quantité de données actuellement stockées sur votre base de données, mais elles ne fournissent pas d’informations sur ses performances ou ses problèmes existants. Pour cela, la méthode beaucoup plus verbeuse serverStatus() est pratique :

  1. db.serverStatus()

La sortie de cette méthode est longue et fournit une grande quantité d’informations sur l’utilisation du serveur :

Output
{ "host" : "ubuntu-mongo-rs", "version" : "4.4.6", "process" : "mongod", "pid" : NumberLong(658997), "uptime" : 976, . . . "ok" : 1 }

Bien que toutes ces informations puissent potentiellement être utiles, ce guide se concentrera sur trois sections en particulier. Tout d’abord, recherchez la section connections de cette sortie :

Output
. . . "connections" : { "current" : 4, "available" : 51196, "totalCreated" : 4, "active" : 2, "exhaustIsMaster" : 1, "exhaustHello" : 0, "awaitingTopologyChanges" : 1 }, . . .

Chaque serveur de base de données peut prendre en charge seulement un certain nombre de connexions à la fois. La clé current montre le nombre de clients actuellement connectés à la base de données, tandis que available est le nombre de connexions inutilisées restantes disponibles pour la base de données. La valeur totalCreated indique le nombre de connexions utilisées depuis le démarrage du serveur.

La plupart des applications sont conçues pour réutiliser les connexions existantes et n’ouvrent pas souvent de nouvelles connexions. Ainsi, un nombre élevé de connexions, s’il n’est pas prévu, peut être un signe alarmant d’une mauvaise configuration de la façon dont les clients accèdent au serveur.

Si un nombre élevé de connexions est prévu par la nature des charges de travail effectuées, vous pouvez envisager d’ajouter un ou plusieurs fragments à un cluster fragmenté pour répartir le trafic sur plusieurs instances MongoDB.

Ensuite, trouvez la section globalLock de la sortie. Cette section concerne les verrous globaux sur l’ensemble du serveur de base de données :

Output
. . . "globalLock" : { "totalTime" : NumberLong(975312000), "currentQueue" : { "total" : 0, "readers" : 0, "writers" : 0 }, "activeClients" : { "total" : 0, "readers" : 0, "writers" : 0 } },

MongoDB utilise des verrous pour garantir la cohérence des données lors de l’exécution de plusieurs opérations, garantissant qu’aucune requête ne modifiera les mêmes données en même temps. Sur des serveurs très sollicités, il est possible que les verrous entraînent des goulets d’étranglement, avec une ou plusieurs requêtes attendant que les verrous soient libérés avant de pouvoir être exécutées.

La valeur currentQueue.total indique le nombre de requêtes en attente de libération des verrous afin qu’elles puissent être exécutées. Si cette valeur est élevée, cela signifie que les performances de la base de données sont affectées et que les requêtes prendront plus de temps à s’exécuter.

Cela découle souvent de nombreuses requêtes longues maintenant les verrous et peut indiquer une utilisation inefficace des index ou des requêtes mal conçues, entre autres possibilités.

Enfin, trouvez la section opcounters:

Output
"opcounters" : { "insert" : NumberLong(10000007), "query" : NumberLong(6), "update" : NumberLong(6), "delete" : NumberLong(0), "getmore" : NumberLong(0), "command" : NumberLong(1298) },

Cette section de la sortie serverStatus() peut vous aider à avoir une idée de savoir si le serveur de base de données est principalement utilisé pour les lectures ou les écritures, ou si son utilisation est bien équilibrée. Dans cet exemple, après l’insertion des documents de test, le compteur pour les opérations insert est beaucoup plus élevé que pour les opérations query. Dans un scénario réel, ces valeurs seraient probablement différentes.

Les bases de données à forte écriture peuvent bénéficier d’une mise à l’échelle horizontale via sharding. De même, les bases de données MongoDB à forte lecture bénéficieront généralement de la réplication.

Ces statistiques peuvent donner une idée générale de l’utilisation du serveur et de l’existence éventuelle de problèmes de performance tels que des files d’attente de verrouillage longues au moment de leur accès. Cependant, elles ne fournissent pas d’informations en temps réel sur l’utilisation du serveur. Pour cela, les commandes mongostat et mongotop sont des outils utiles.

Étape 3 — Utilisation de mongostat et mongotop pour obtenir des statistiques de base de données en temps réel

Alors que les commandes utilisées pour accéder aux statistiques du serveur MongoDB peuvent fournir des informations sur la façon dont le serveur est utilisé rétrospectivement, elles ne peuvent pas fournir d’informations en temps réel sur les collections les plus activement utilisées à l’instant présent ou sur le type de requêtes en cours d’exécution.

MongoDB fournit deux outils système utiles pour la surveillance en temps réel qui analysent l’activité de la base de données et rafraîchissent continuellement les informations qu’ils fournissent : mongostat et mongotop. mongostat fournit un bref aperçu de l’état actuel de l’instance MongoDB, tandis que mongotop suit le temps passé par l’instance sur les opérations de lecture et d’écriture. Ces deux outils sont exécutés à partir de la ligne de commande, plutôt que du shell MongoDB.

Pour utiliser mongostat, gardez votre connexion shell MongoDB actuelle et ouvrez une autre fenêtre de terminal pour accéder à votre shell serveur. Dans le deuxième shell serveur, exécutez la commande mongostat:

  1. mongostat -u AdminSammy --authenticationDatabase admin

Comme mentionné précédemment, mongostat nécessite des privilèges avancés. Si vous avez activé l’authentification sur votre instance MongoDB et configuré un utilisateur avec les rôles appropriés, vous devrez alors vous authentifier en tant que cet utilisateur en fournissant leur nom d’utilisateur et la base de données d’authentification (comme illustré dans cet exemple) puis en entrant leur mot de passe lorsqu’on vous le demande.

Dans une configuration par défaut, mongostat affiche les compteurs des requêtes actuellement exécutées à des intervalles d’une seconde :

Output
insert query update delete getmore command dirty used flushes vsize res qrw arw net_in net_out conn time *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.4k 7 Nov 28 15:40:40.621 *0 *0 *0 *0 0 2|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 224b 84.8k 7 Nov 28 15:40:41.619 *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.5k 7 Nov 28 15:40:42.621 *0 *0 *0 *0 0 3|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 365b 85.0k 7 Nov 28 15:40:43.619

Si la sortie de mongostat montre une valeur de 0 pour un type de requête donné, cela indique que la base de données ne traite aucune opération de ce type. Cet exemple de sortie montre 0 pour chaque type de requête, ce qui signifie qu’il n’y a actuellement aucune requête en cours d’exécution.

Vous devriez toujours avoir votre première fenêtre de terminal ouverte et connectée à votre shell MongoDB. Insérez quelques documents de test supplémentaires dans la collection accounts et vérifiez si mongostat détectera l’activité :

  1. for (let i = 1; i <= 10000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "2000-" + i,
  4. "currency": "USD",
  5. "balance": Math.random() * 100000
  6. })
  7. }

Il s’agit d’une boucle for similaire à celle que vous avez exécutée à l’étape 1. Cette fois, cependant, la boucle n’insère que 10000 entrées. Les numéros de compte sont précédés de 2000, et la devise est toujours USD.

Pendant l’insertion des nouveaux documents, vérifiez la sortie de mongostat :

Output
. . . *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 112b 42.5k 4 Nov 28 15:50:33.294 *0 *0 *0 *0 0 0|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:34.295 755 *0 *0 *0 0 1|0 0.1% 38.8% 0 1.54G 210M 0|0 1|0 154k 79.4k 4 Nov 28 15:50:35.294 2853 *0 *0 *0 0 0|0 0.4% 39.1% 0 1.54G 211M 0|0 1|0 585k 182k 4 Nov 28 15:50:36.295 2791 *0 *0 *0 0 1|0 0.7% 39.4% 0 1.54G 212M 0|0 1|0 572k 179k 4 Nov 28 15:50:37.293 2849 *0 *0 *0 0 0|0 1.0% 39.7% 0 1.54G 213M 0|0 1|0 584k 182k 4 Nov 28 15:50:38.296 745 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 153k 79.2k 4 Nov 28 15:50:39.294 *0 *0 *0 *0 0 0|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:40.295 *0 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 167b 42.7k 4 Nov 28 15:50:41.293 . . .

Pendant que la requête s’exécute, les nouvelles lignes renvoyées par mongostat commencent à afficher des valeurs autres que 0. Dans la colonne insert montrant le nombre de requêtes insérant de nouvelles données dans la base de données, les valeurs étaient plus élevées pendant plusieurs secondes. Étant donné que mongostat affiche les données à des intervalles d’une seconde, vous pouvez non seulement trouver la proportion d’insertions par rapport aux autres types d’opérations de base de données, mais aussi la vitesse à laquelle la base de données insère les nouvelles données. Dans cet exemple, le serveur a réalisé presque 3000 insertions par seconde.

Vous pouvez utiliser mongostat pour surveiller la charge de travail actuelle du serveur de base de données, regroupée par types de requêtes. Le deuxième outil fourni avec MongoDB, mongotop, montre l’activité du serveur de base de données regroupée par collections.

Arrêtez l’exécution de mongostat dans votre deuxième fenêtre de terminal en appuyant sur CTRL + C. Ensuite, exécutez mongotop dans ce même terminal. Encore une fois, si vous avez l’authentification activée, vous devrez vous authentifier en tant qu’utilisateur disposant des privilèges appropriés:

  1. mongotop -u AdminSammy --authenticationDatabase admin

mongotop produit une liste de toutes les collections de la base de données, accompagnée du temps passé en lecture, en écriture et en totalité dans la fenêtre temporelle. De manière similaire à mongostat, la sortie est actualisée chaque seconde:

Output
2021-11-28T15:54:42.290+0000 connected to: mongodb://localhost/ ns total read write 2021-11-28T15:54:43Z admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms test.accounts 0ms 0ms 0ms . . .

Essayez d’insérer d’autres documents dans la base de données pour voir si l’activité est enregistrée dans mongotop. Dans l’interpréteur de commandes MongoDB, exécutez la boucle for suivante ; après cela, observez la fenêtre de terminal avec mongotop en cours d’exécution:

  1. for (let i = 1; i <= 10000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "3000-" + i,
  4. "currency": "USD",
  5. "balance": Math.random() * 100000
  6. })
  7. }

Cette fois, l’activité sera visible dans les statistiques de mongotop.

Output
. . . ns total read write 2021-11-28T15:57:27Z test.accounts 127ms 0ms 127ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms ns total read write 2021-11-28T15:57:28Z test.accounts 130ms 0ms 130ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms . . .

Voici, mongotop montre que toute l’activité de la base de données s’est déroulée dans la collection accounts de la base de données test et que toutes les opérations dans la fenêtre de temps ont été des opérations d’écriture. Tout cela devrait correspondre à l’opération de la boucle for que vous avez exécutée.

Tout comme avec mongostat, vous pouvez arrêter mongotop en appuyant sur CTRL + C.

Lorsqu’il est observé pendant une charge de pointe, vous pouvez utiliser mongotop pour surveiller comment l’activité de la base de données se répartit entre différentes collections afin de mieux comprendre votre schéma et de planifier l’évolutivité. Il fournit également un aperçu de savoir si l’utilisation d’une collection est plus orientée vers la lecture ou l’écriture.

Étape 4 — Utilisation du profileur de base de données de MongoDB pour identifier les requêtes lentes

Les goulots d’étranglement des performances de la base de données peuvent provenir de nombreuses sources. Bien que le redimensionnement de la base de données (horizontalement ou verticalement) soit souvent la solution aux goulots d’étranglement des performances, leur cause peut en réalité être des problèmes avec le schéma ou la conception de la requête.

Si les requêtes prennent trop de temps, la cause peut être une utilisation inefficace des index ou des erreurs dans la requête elle-même. Les requêtes longues passent souvent inaperçues pendant le développement de l’application, généralement parce que les jeux de données de test sont trop petits ou que les conditions sont différentes de celles de la production.

Vous pourriez potentiellement trouver le coupable en exécutant manuellement des requêtes de test et en vérifiant lesquelles sont sous-performantes, bien que cela soit très fastidieux. Heureusement, l’outil de profilage de la base de données de MongoDB peut le faire automatiquement.

Le profileur de base de données de MongoDB peut enregistrer les requêtes et les statistiques concernant leur exécution lorsqu’elles correspondent à certaines conditions. La plus importante de ces conditions est le temps d’exécution de la requête : si une requête prend plus de temps qu’un certain seuil pour s’exécuter, le profileur la signalera automatiquement comme problématique. En utilisant le profileur, vous pouvez identifier les requêtes qui s’exécutent mal, puis vous concentrer sur la résolution de ces problèmes particuliers.

Avant d’utiliser le profileur, exécutez la requête suivante. Cette requête récupérera l’un des comptes que vous avez insérés, bien qu’elle ne soit pas aussi simple qu’il n’y paraît au premier abord :

  1. db.accounts.find({"number": "1000-20"})

La commande récupérera le compte exact que vous avez demandé :

Output
{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }

Vous avez peut-être remarqué que la requête n’a pas été exécutée immédiatement et qu’il a fallu à MongoDB un moment ou deux pour trouver le compte. Dans une application du monde réel, il pourrait y avoir de nombreux types de requêtes qui s’exécutent mal, et vous pourriez ne pas remarquer leur sous-performance en pratique.

Vous pouvez configurer MongoDB pour vous aider à identifier quelles requêtes prennent plus de temps que prévu. Pour ce faire, activez d’abord le profileur en exécutant la commande suivante :

  1. db.setProfilingLevel(1, { slowms: 100 })

La méthode setProfilingLevel() prend deux arguments. Le premier est le niveau de profilage, qui peut être soit 0, 1, ou 2 :

  • 0 désactive le profileur
  • 1 active le profileur uniquement sur les requêtes lentes satisfaisant la condition
  • 2 active le profileur pour toutes les requêtes

Dans cet exemple, le profileur analysera les requêtes qui s’exécutent pendant plus de 100 millisecondes, tel que défini par le deuxième argument, { slowms: 100 }.

Note : L’utilisation du profileur dégrade les performances, car MongoDB doit maintenant analyser les requêtes en plus de les exécuter. Il convient de l’utiliser avec parcimonie lors du suivi des goulots d’étranglement de performance.

Il est possible de personnaliser davantage le sous-ensemble des requêtes que le profileur va enregistrer en le configurant pour profiler uniquement un certain pourcentage de requêtes ou en filtrant par type de requête. Pour en savoir plus sur la manière dont vous pouvez avoir un plus grand contrôle sur le profileur, référez-vous à la documentation officielle sur le sujet.

Cette méthode renverra un message de succès :

Output
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }

Désormais, le profilage de la base de données sera activé et MongoDB surveillera activement chaque requête que vous exécutez pour trouver celles qui prennent plus de 100 millisecondes pour se terminer.

Essayez cela en exécutant quelques requêtes différentes. Tout d’abord, utilisez la commande count pour trouver le nombre de documents dans la collection accounts :

  1. db.accounts.count()

Cette commande retournera rapidement le nombre de documents dans la collection :

Output
1020000

Ensuite, essayez de rechercher les trois premiers comptes bancaires apparaissant dans la collection :

  1. db.accounts.find().limit(3)

Encore une fois, la base de données renverra rapidement les résultats :

Output
{ "_id" : ObjectId("61ef40640f2ba52efc56ee17"), "number" : "1000-1", "currency" : "EUR", "balance" : 25393.132960293842 } { "_id" : ObjectId("61ef40640f2ba52efc56ee18"), "number" : "1000-2", "currency" : "EUR", "balance" : 63629.42056192393 } { "_id" : ObjectId("61ef40640f2ba52efc56ee19"), "number" : "1000-3", "currency" : "EUR", "balance" : 75602.12331602155 }

Enfin, exécutez à nouveau la requête de recherche pour le compte bancaire particulier :

  1. db.accounts.find({"number": "1000-20"})

Cette requête retournera le résultat mais, comme précédemment, cela prendra un moment ou deux de plus que les opérations précédentes.

Output
{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }

Le profileur ne produit aucune sortie propre même si la requête était visiblement plus lente. Au lieu de cela, les détails sur les opérations lentes sont enregistrés dans une collection spéciale au sein de la base de données nommée system.profile. Cette collection est une collection limitée qui ne dépasse jamais 1 Mo de taille. Cela signifie qu’elle contiendra toujours une liste uniquement des requêtes les plus récentes et lentes.

Pour récupérer des informations sur les requêtes identifiées par le profileur, vous devez interroger la collection system.profile de la manière suivante :

  1. db.system.profile.find().sort({ "ts" : -1 }).pretty()

Cette requête utilise la méthode find(), comme d’habitude. Elle inclut également une clause sort qui contient { "ts" : -1 } comme argument. Cela triera l’ensemble de résultats avec les requêtes les plus récentes en premier. Enfin, la méthode pretty() à la fin affichera la sortie dans un format plus lisible.

Chaque requête lente est représentée sous forme de document régulier, et system.profile est comme n’importe quelle collection régulière. Cela signifie que vous pouvez filtrer les résultats, les trier et même les utiliser dans des pipelines d’agrégation pour réduire davantage ou analyser la liste des requêtes identifiées par le profileur.

Remarquez que le résultat ne consiste qu’en un seul document. Les deux autres requêtes ont été exécutées assez rapidement pour ne pas déclencher le profileur :

Output
{ "op" : "query", "ns" : "test.accounts", "command" : { "find" : "accounts", "filter" : { "number" : "1000-20" }, . . . }, "nreturned" : 1, "keysExamined" : 0, "docsExamined" : 1030000, . . . "millis" : 434, "planSummary" : "COLLSCAN", . . . }

Cette sortie fournit un certain nombre de détails sur l’exécution de la requête lente :

  • La clé op montre quel type d’opération cette information représente. Ici, c’est une query, car elle représente une opération dans laquelle vous avez utilisé la fonction find() pour récupérer des données de la base de données.
  • La clé ns indique quelle base de données et quelle collection étaient impliquées dans l’opération. Comme le montre la sortie, cette opération a interrogé la collection accounts dans la base de données test.
  • La clé command fournit des informations supplémentaires sur la requête elle-même. Dans ce cas, le sous-champ filter contient l’ensemble du document de filtre. En utilisant les informations provenant des champs op et command, vous pouvez reconstruire la requête en question.
  • Dans le champ millis, vous trouverez le temps exact nécessaire pour terminer la requête. Dans cet exemple, presque une demi-seconde.
  • Le champ docsExamined fournit le nombre de documents analysés pour retourner l’ensemble de résultats.
  • nreturned représente le nombre de documents retournés par la requête. Dans cet exemple, un seul document a été retourné sur plus d’un million analysés.
  • Le planSummary montre la méthode utilisée par MongoDB pour exécuter la requête. COLLSCAN correspond à un balayage complet de la collection, ce qui signifie qu’il a parcouru chaque document de la collection un par un pour trouver le compte bancaire correspondant.

Toutes ces informations soulignent la nécessité d’un index qui pourrait aider MongoDB à exécuter cette requête plus rapidement. La base de données a dû parcourir toute la collection pour trouver un seul document, comme l’indique la grande différence entre le nombre de documents examinés et retournés, ainsi que la stratégie d’exécution.

Dans cet exemple particulier, la création d’un index pour prendre en charge les requêtes filtrant les données en fonction du champ number fournirait un coup de pouce immédiat aux performances de ce type de requêtes. Dans des scénarios réels, les solutions aux requêtes lentes peuvent différer et dépendre de la requête exacte qui pose problème.

Pour terminer la session de profilage, vous pouvez désactiver le profileur en définissant le niveau de profilage sur zéro :

  1. db.setProfilingLevel(0)

L’opération réussira avec un message de confirmation :

Output
{ "was" : 1, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }

Maintenant, la base de données revient à un fonctionnement normal sans qu’aucun profilage ne se produise en arrière-plan.

Chaque fois que vous soupçonnez que des requêtes lentes peuvent avoir un impact négatif sur les performances de votre base de données, vous pouvez utiliser le profileur de base de données pour les trouver et mieux comprendre leur structure et leur mode d’exécution. Avec ces informations, vous serez mieux équipé pour les ajuster et améliorer leurs performances.

Conclusion

En suivant ce guide, vous avez appris à trouver les statistiques du serveur MongoDB et à utiliser des outils de diagnostic tels que mongotop, mongostat, ainsi que le mécanisme de profilage de la base de données MongoDB. Vous pouvez utiliser ces outils pour avoir une meilleure idée de la charge de travail de votre base de données, déterminer quelles collections sont les plus actives, et savoir si le serveur effectue principalement des écritures ou des lectures. Vous pouvez également identifier les requêtes lentes qui affectent les performances de MongoDB afin de les remplacer par des requêtes plus efficaces.

Il ne s’agit que d’une sélection d’outils et de techniques que vous pouvez utiliser pour surveiller la santé et les performances de votre installation MongoDB et agir en conséquence. Chacun de ces outils peut être configuré et personnalisé davantage pour vous fournir des informations plus ciblées sur les performances du serveur. Nous vous encourageons à consulter la documentation officielle de MongoDB pour en savoir plus sur les techniques que vous pouvez utiliser pour surveiller les performances du serveur et agir en conséquence.

Source:
https://www.digitalocean.com/community/tutorials/how-to-monitor-mongodb-s-performance