background success stories

Tracer les requêtes lentes sous MongoDB

MongoDB ne déroge pas à la règle comme sur les autres SGBDs il convient parfois pour des raisons d’optimisations d’activer le slow query. Ce dernier étant désactivé par défaut, il nous faut effectuer des manipulations pour le mettre en place.

Mais tout d’abord il faut savoir que contrairement à une grande partie de ses concurrents, nous pouvons l’activer uniquement sur certaines bases (ce qui évite de consommer des ressources inutilement).

Pour obtenir la liste des bases une fois connecté au terminal mongo, il nous suffit de taper la commande suivante :

> show databases
admin 		0.000GB
baseTest 	10.10GB
config 		0.000GB
local     	0.000GB

Les bases admin, config, local sont des bases internes à MongoDB nous n’allons pas activer le slow query sur ces dernières.

Se positionner dans une base applicative sur laquelle vous souhaitez activer la capture des requêtes lentes :

> use baseTest
switched to db baseTest

Ensuite vérifier l’état du « profiling level » (afin d’être sûr qu’un de vos consultants ne l’aurait pas activé par le passé)

> db.getProfilingStatus()
{ "was" : 0, "slowms" : 100 }

Si la valeur « was » retournée est :

  • 0 : la capture de requête est désactivée, néanmoins MongoDB va écrire dans le log d’erreur toutes les requêtes supérieur à 100 ms par défaut. Le principal inconvénient de cette option est que le log d’erreur sous MongoDB est très verbeux, il est donc assez fastidieux de retrouver les requêtes tracées.
  • 1 : la capture des requêtes est déjà activée pour cette base uniquement.
  • 2 : la capture des requêtes est déjà activée sur toutes les bases (ceci va dégrader inutilement les performances), nous allons préférer nous concentrer sur les bases que vous souhaitez étudier.

Si la capture des requêtes lentes est activé, vous devriez avoir une collection nommée system.profile. C’est dans cette collection que MongoDB va stocker les requêtes lentes.

> show collections

Cette collection est un peu particulière car il s’agit une capped collection, ou une collection dite « collection circulaire/plafonnée/ à taille fixe ».

Concrètement ceci signifie qu’une fois la taille limite atteinte (1Mb par défaut, mais il est possible à sa création de lui avoir fixé une taille plus importante) la collection va écraser les plus anciens éléments afin d’insérer les nouveaux.

Les slow queries sont stockées dans ce type de collection afin de prendre le moins de place possible. Ceci nous évite de faire des purges manuellement et si jamais un mauvais paramétrage au niveau du seuil de la capture avait été effectué ceci aurait pu amener à une saturation de l’espace disque.

Plus d’informations sur les Capped Collection sur : https://docs.mongodb.com/manual/core/capped-collections/

Vous pouvez interroger cette collection de manière classique :

  • Voir les 20 dernières requêtes lentes capturées :
> db.system.profile.find().limit(20).sort( { ts : -1 } ).pretty()
  • Voir toutes les requêtes supérieur à 1 seconde :
> db.system.profile.find( { millis : { $gt : 1000 } } ).pretty()

Si le profiling n’est pas activé, il nous faut nous en charger

db.setProfilingLevel(1,seuil_de_capture_en_ms)

Le seuil de capture est appelé aussi appelé slowms.

Attention concernant le positionnement du seuil de capture, il ne faut pas positionner ce dernier avec une valeur :

  • trop basse car sinon on sera « pollué » par x requêtes sans intérêt de plus enregistrer les requêtes a un impact négatif au niveau des performances
  • trop haute car sinon nous n’aurons aucune requête à analyser de surcroît une requête très récurrente même avec un temps jugé acceptable est toujours intéressante à analyser.

Exemple : Pour capturer toutes les requêtes supérieurs à 1 seconde : db.setProfilingLevel(1, 1000)

Vérifier que le profiling est bien activé avec la commande:

> db.getProfilingStatus()
{ "was" : 1, "slowms" : seuil_que_vous_avez_définit }

En fonction de l’activité sur vos bases (quelques minutes ou quelques heures après avoir activé le slow query), vérifier que la capture des requêtes lentes est bien opérationnelle.

> db.system.profile.find()

Si jamais vous estimez ne pas avoir assez de requêtes ou au contraire avoir trop de requêtes (en d’autre terme le seuil de capture a été mal positionné), vous pouvez modifier la valeur slowms en réexécutant la fonction db.setProfilingLevel(1,slowms).

Répéter les opérations précédentes pour toutes les bases applicatives que vous souhaitez étudier.

Une fois que vous avez collectés suffisamment de requête, vous pouvez désactiver le profiling avec la commande :

> db.setProfilingLevel(0)

Vous devriez avoir un ok à 1 en retour de commande (les autres valeurs ne nous intéresse guère):

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

Les données collectées ne sont pas supprimées, vous pouvez toujours les interroger.

Ensuite si vous estimez ne plus en avoir l’utilité, vous pouvez la supprimer.

> db.system.profile.drop()

Si jamais vous souhaitez des conseils d’optimisations ou un audit de votre architecture n’hésitez pas à nous contacter.