Cómo supervisar el rendimiento de MongoDB

El autor seleccionó el Fondo de Internet Abierto/Libertad de Expresión para recibir una donación como parte del programa Escribir para Donaciones.

Introducción

La monitorización es una parte clave de la administración de bases de datos, ya que te permite entender el rendimiento y la salud general de tu base de datos. Al monitorizar el rendimiento de tu base de datos, puedes tener una mejor idea de su capacidad actual, observar cómo cambia su carga de trabajo con el tiempo y planificar el escalado de la base de datos una vez que comience a acercarse a sus límites. También puede ayudarte a detectar problemas de hardware subyacentes o comportamientos anormales como un pico inesperado en el uso de la base de datos. Por último, la monitorización puede ayudar a diagnosticar problemas con las aplicaciones que utilizan la base de datos, como consultas de aplicaciones que causan cuellos de botella.

MongoDB viene instalado con una variedad de herramientas y utilidades que puedes utilizar para observar el rendimiento de tu base de datos. En este tutorial, aprenderás cómo monitorizar métricas de la base de datos bajo demanda utilizando comandos y herramientas integradas. También te familiarizarás con el perfilador de base de datos de MongoDB que puede ayudarte a detectar consultas mal optimizadas.

Requisitos previos

Para seguir este tutorial, necesitarás:

  • A server with a regular, non-root user with sudo privileges and a firewall configured with UFW. This tutorial was validated using a server running Ubuntu 20.04, and you can prepare your server by following this initial server setup tutorial for Ubuntu 20.04.
  • MongoDB instalado en tu servidor. Para configurarlo, sigue nuestro tutorial sobre Cómo Instalar MongoDB en Ubuntu 20.04.
  • La instancia de MongoDB en tu servidor debe estar asegurada mediante la habilitación de la autenticación y la creación de un usuario administrativo. Para asegurar MongoDB de esta manera, sigue nuestro tutorial sobre Cómo Asegurar MongoDB en Ubuntu 20.04.
  • Familiaridad con la consulta de colecciones MongoDB y la filtración de resultados. Para aprender cómo usar consultas en MongoDB, sigue nuestra guía sobre Cómo Crear Consultas en MongoDB.

Nota: Los tutoriales vinculados sobre cómo configurar tu servidor, instalar MongoDB y asegurar la instalación de MongoDB hacen referencia a Ubuntu 20.04. Este tutorial se concentra en MongoDB en sí mismo, no en el sistema operativo subyacente. Funcionará en general con cualquier instalación de MongoDB independientemente del sistema operativo siempre que se haya habilitado la autenticación.

Paso 1 — Preparar los Datos de Prueba

Para explicar cómo puedes monitorear el rendimiento de MongoDB, este paso describe cómo abrir la consola de MongoDB para conectarte a tu instancia de MongoDB instalada localmente y crear una colección de muestra dentro de ella.

Para crear la colección de muestra utilizada en esta guía, conéctate a la shell de MongoDB como tu usuario administrativo. Este tutorial sigue las convenciones del tutorial de seguridad de MongoDB necesario y asume que el nombre de este usuario administrativo es AdminSammy y su base de datos de autenticación es admin. Asegúrate de cambiar estos detalles en el siguiente comando para reflejar tu propia configuración, si es diferente:

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

Ingresa la contraseña establecida durante la instalación para acceder a la shell. Después de proporcionar la contraseña, verás el signo de prompt >.

Nota: En una conexión nueva, la shell de MongoDB se conectará a la base de datos test de manera predeterminada. Puedes utilizar esta base de datos de forma segura para experimentar con MongoDB y la shell de MongoDB.

Alternativamente, podrías cambiar a otra base de datos para ejecutar todos los comandos de ejemplo dados en este tutorial. Para cambiar a otra base de datos, ejecuta el comando use seguido del nombre de tu base de datos:

  1. use database_name

El monitoreo de la base de datos no es muy práctico ni útil cuando se trabaja con un conjunto de datos pequeño, ya que el sistema de base de datos solo necesitará escanear unos pocos registros para cualquier consulta dada. Para ilustrar las características de monitoreo de rendimiento de MongoDB, necesitarás una base de datos con suficientes datos para que MongoDB tarde un tiempo significativo en ejecutar consultas.

Con este fin, los ejemplos a lo largo de esta guía se refieren a una colección de muestra llamada accounts que contiene una gran cantidad de documentos. Cada documento representa una cuenta bancaria individual con un saldo de cuenta generado aleatoriamente. Cada documento en la colección tendrá una estructura como esta:

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

Este documento de ejemplo contiene la siguiente información:

  • número: Este campo representa el número de cuenta para la cuenta dada. En esta colección, cada número de cuenta tendrá un prefijo de 1000- seguido de un identificador numérico en aumento.
  • moneda: Este campo indica en qué tipo de moneda se almacena el saldo de cada cuenta. El valor de moneda de cada cuenta será USD o EUR.
  • saldo: Esto muestra el saldo para cada cuenta bancaria dada. En esta base de datos de muestra, el campo saldo de cada documento tendrá un valor generado aleatoriamente.

En lugar de insertar manualmente una gran cantidad de documentos, puedes ejecutar el siguiente código JavaScript para crear simultáneamente una colección llamada accounts e insertar un millón de dichos documentos en ella:

  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. }

Este código ejecuta un bucle for que se repite un millón de veces seguidas. Cada vez que el bucle itera, ejecuta un método insertOne() en la colección de cuentas para insertar un nuevo documento. En cada iteración, el método asigna un valor al campo number compuesto por el prefijo 1000- con el valor contenido en la variable i para esa iteración. Esto significa que la primera vez que se ejecuta este bucle, el valor del campo number será establecido como 1000-1; la última vez que itere, será establecido como 1000-1000000.

La moneda siempre se representa como USD para cuentas con números superiores a 500000 y como EUR para cuentas con números inferiores a eso. El campo de saldo utiliza la función Math.random() para generar un número aleatorio entre 0 y 1, y luego multiplica el número aleatorio por 100000 para proporcionar valores más grandes.

Nota: Ejecutar este bucle puede llevar mucho tiempo, incluso más de 10 minutos. Es seguro dejar la operación en ejecución hasta que termine.

La salida te informará del éxito y devolverá el ObjectId del último documento que se insertó:

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

Puedes verificar que los documentos se insertaron correctamente ejecutando el método count() sin argumentos, que recuperará el recuento de documentos en la colección:

  1. db.accounts.count()
Output
1000000

En este paso, has creado con éxito la lista de documentos de ejemplo que servirán como datos de prueba utilizados en esta guía para explicar las herramientas que MongoDB proporciona para el monitoreo del rendimiento. En el próximo paso, aprenderás cómo verificar las estadísticas básicas de uso del servidor.

Paso 2 — Verificación de las estadísticas de uso del servidor

MongoDB realiza un seguimiento automático de una serie de estadísticas de rendimiento útiles, y verificarlas regularmente es una forma fundamental de monitorear su base de datos. Tenga en cuenta que estas estadísticas no ofrecerán información en tiempo real sobre lo que está sucediendo con su base de datos, pero pueden ser útiles para determinar cómo se desempeña la base de datos y si hay algún problema inminente.

Advertencia: Los comandos de monitoreo de MongoDB descritos en esta guía devuelven información potencialmente sensible sobre su base de datos y su rendimiento. Debido a esto, algunos de estos comandos requieren permisos avanzados.

Específicamente, el método serverStatus() descrito en este paso, así como los comandos mongostat y mongotop resaltados en el siguiente paso, requieren que los usuarios hayan sido otorgados el rol clusterMonitor para ejecutarlos. Del mismo modo, el método setProfilingLevel() descrito en el Paso 4 requiere el rol dbAdmin.

Suponiendo que haya seguido el tutorial previo sobre Cómo asegurar MongoDB en Ubuntu 20.04 y esté conectado a su instancia de MongoDB como el usuario administrativo que creó en esa guía, deberá otorgarle estos roles adicionales para seguir los ejemplos en esta guía.

Primero, cambie a la base de datos de autenticación de su usuario. Esto es admin en el siguiente ejemplo, pero conéctese a su propia base de datos de autenticación si es diferente:

  1. use admin
Output
switched to db admin

Luego, ejecute un método grantRolesToUser() y otorgue a su usuario el rol clusterMonitor junto con el rol dbAdmin sobre la base de datos donde creó la colección accounts. El siguiente ejemplo asume que la colección accounts está en la base de datos test:

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

Tenga en cuenta que generalmente se considera más seguro tener perfiles de usuario dedicados a propósitos específicos. De esta manera, ningún usuario tendrá privilegios innecesariamente amplios. Si está trabajando en un entorno de producción, es posible que desee tener un usuario dedicado cuyo único propósito sea monitorear la base de datos.

El siguiente ejemplo crea un usuario de MongoDB llamado MonitorSammy y les otorga los roles necesarios para que pueda seguir los ejemplos de este tutorial. Tenga en cuenta que también incluye el rol readWriteAnyDatabase, que permitirá a este usuario leer y escribir datos en cualquier base de datos del clúster:

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

Después de otorgar a su usuario los roles apropiados, navegue de vuelta a la base de datos donde se encuentra su colección accounts:

  1. use test
Output
switched to db test

Comience por verificar las estadísticas generales de la base de datos ejecutando el método stats():

  1. db.stats(1024*1024)

El argumento de este método (1024*1024) es el factor de escala y le indica a MongoDB que devuelva información de almacenamiento en megabytes. Si omite esto, los valores se presentarán todos en bytes.

El método stats() devuelve una salida corta y concisa con algunas estadísticas importantes relacionadas con la base de datos actual:

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 }

Esta salida proporciona una visión general de los datos que esta instancia de MongoDB está almacenando. Las siguientes claves devueltas en esta salida pueden ser particularmente útiles:

  • La clave objects muestra el número total de documentos en la base de datos. Puede utilizar esto para evaluar el tamaño de la base de datos y, cuando se observa con el tiempo, su crecimiento.
  • avgObjectSize muestra el tamaño promedio de estos documentos, ofreciendo información sobre si la base de datos está operando con documentos grandes y complejos o pequeños. Este valor siempre se muestra en bytes, independientemente de si especifica un factor de escala.
  • Las claves collections y indexes indican cuántas colecciones e índices están actualmente definidos en la base de datos.
  • La clave totalSize indica cuánto almacenamiento ocupa la base de datos en disco.

Esta información devuelta por el método stats() puede ayudar a tener una idea de cuántos datos se almacenan actualmente en su base de datos, pero no proporciona información sobre su rendimiento o problemas existentes. Para eso, el método serverStatus(), mucho más detallado, resulta útil:

  1. db.serverStatus()

La salida de este método es extensa y proporciona una gran cantidad de información sobre el uso del servidor:

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

Aunque toda esta información podría ser potencialmente útil, esta guía se centrará en tres secciones en particular. Primero, busque la sección connections de esta salida:

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

Cada servidor de base de datos puede admitir solo un número limitado de conexiones a la vez. La clave current muestra el número de clientes actualmente conectados a la base de datos, mientras que available es el número de conexiones no utilizadas restantes que la base de datos tiene disponibles. El valor de totalCreated guarda el número de conexiones utilizadas desde el inicio del servidor.

La mayoría de las aplicaciones están diseñadas para reutilizar conexiones existentes y no abren múltiples conexiones con frecuencia. Por lo tanto, un alto número de conexiones, si no se anticipa, puede ser una señal alarmante de una mala configuración en cómo los clientes acceden al servidor.

Si se anticipa un alto número de conexiones debido al tipo de cargas de trabajo realizadas, puede considerar agregar uno o más fragmentos a un clúster fragmentado para distribuir el tráfico entre múltiples instancias de MongoDB.

A continuación, encuentre la sección globalLock de la salida. Esta sección se relaciona con los bloqueos globales en todo el servidor de la base de datos:

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

MongoDB utiliza bloqueos para garantizar la consistencia de los datos al realizar múltiples operaciones, garantizando que no haya dos consultas que modifiquen los mismos datos al mismo tiempo. En servidores muy utilizados, existe la posibilidad de que los bloqueos resulten en cuellos de botella, con una o más consultas esperando a que se liberen los bloqueos antes de que puedan ejecutarse.

El valor de currentQueue.total muestra el número de consultas esperando a que se liberen los bloqueos para que puedan ejecutarse. Si este valor es alto, significa que el rendimiento de la base de datos se está viendo afectado y las consultas tardarán más en completarse.

Esto a menudo se deriva de muchas consultas prolongadas que mantienen los bloqueos y puede ser indicativo de un uso ineficaz de índices o consultas mal diseñadas, entre otras posibilidades.

Por último, encuentra la sección opcounters:

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

Esta sección de la salida de serverStatus() puede ayudarte a tener una idea de si el servidor de base de datos se utiliza principalmente para lecturas o escrituras, o si su uso está bien equilibrado. En este ejemplo, después de insertar los documentos de prueba, el contador de operaciones de insert es mucho más alto que el de operaciones de query. En un escenario de la vida real, es probable que estos valores sean diferentes.

Las bases de datos con muchas escrituras pueden beneficiarse de la escalabilidad horizontal a través de sharding. Del mismo modo, las bases de datos MongoDB con muchas lecturas generalmente se beneficiarán de la replicación.

Estas estadísticas pueden dar una idea general de cómo se utiliza el servidor y si hay problemas de rendimiento, como colas de bloqueo largas en el momento de acceder a ellas. Sin embargo, no proporcionan información en tiempo real sobre cómo se utiliza el servidor. Para eso, los comandos mongostat y mongotop son herramientas útiles.

Paso 3 — Utilizando mongostat y mongotop para Obtener Estadísticas de la Base de Datos en Tiempo Real

Mientras que los comandos utilizados para acceder a las estadísticas del servidor de MongoDB pueden proporcionar información retrospectiva sobre cómo se utiliza el servidor, no pueden proporcionar información en tiempo real sobre qué colecciones se están utilizando más activamente en ese momento o qué tipo de consultas se están ejecutando.

MongoDB proporciona dos herramientas del sistema útiles para el monitoreo en tiempo real que analizan la actividad de la base de datos y actualizan continuamente la información que proporcionan: mongostat y mongotop. mongostat proporciona una breve descripción general del estado actual de la instancia de MongoDB, mientras que mongotop realiza un seguimiento del tiempo que la instancia pasa en operaciones de lectura y escritura. Ambas herramientas se ejecutan desde la línea de comandos, en lugar de desde la shell de MongoDB.

Para utilizar mongostat, mantenga su conexión actual de la shell de MongoDB y abra otra ventana de terminal para acceder a la shell de su servidor. En la segunda shell del servidor, ejecute el comando mongostat:

  1. mongostat -u AdminSammy --authenticationDatabase admin

Como se mencionó anteriormente, mongostat requiere privilegios avanzados. Si has habilitado la autenticación en tu instancia de MongoDB y has configurado un usuario con los roles apropiados, entonces tendrás que autenticarte como ese usuario proporcionando su nombre de usuario y la base de datos de autenticación (como se muestra en este ejemplo) y luego ingresar su contraseña cuando se solicite.

En una configuración predeterminada, mongostat imprime los contadores de las consultas actualmente ejecutadas en intervalos de un segundo:

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 salida de mongostat muestra un valor de 0 para un tipo de consulta dado, indica que la base de datos no está ejecutando ninguna operación de ese tipo. Esta salida de ejemplo muestra 0 para cada tipo de consulta, lo que significa que actualmente no hay consultas en ejecución.

Aún debes tener abierta tu primera ventana de terminal y conectada a tu shell de MongoDB. Inserta algunos documentos de prueba más en la colección accounts y verifica si mongostat notará la actividad:

  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. }

Este es un bucle for similar al que ejecutaste en el Paso 1. Sin embargo, esta vez, el bucle inserta solo 10000 entradas. Los números de cuenta tienen el prefijo 2000, y la moneda siempre es USD.

Mientras se están insertando los nuevos documentos, verifica la salida 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 . . .

Mientras se ejecuta la consulta, las nuevas líneas devueltas por mongostat comienzan a mostrar valores distintos de 0. En la columna insert, que muestra el número de consultas que están insertando nuevos datos en la base de datos, los valores fueron más altos durante varios segundos. Dado que mongostat muestra datos en intervalos de un segundo, puedes encontrar no solo la proporción de inserciones con respecto a otros tipos de operaciones de base de datos, sino también qué tan rápido inserta la base de datos los nuevos datos. En este ejemplo, el servidor logró casi 3000 inserciones por segundo.

Puedes utilizar mongostat para monitorear la carga actual del servidor de base de datos, agrupada por tipos de consulta. La segunda herramienta que MongoDB incluye, mongotop, muestra la actividad del servidor de base de datos agrupada por colecciones.

Detén la ejecución de mongostat en tu segunda ventana de terminal presionando CTRL + C. Luego ejecuta mongotop en esa misma terminal. Nuevamente, si tienes la autenticación habilitada, deberás autenticarte como usuario con los privilegios adecuados:

  1. mongotop -u AdminSammy --authenticationDatabase admin

mongotop muestra una lista de todas las colecciones en la base de datos, acompañadas del tiempo dedicado a lecturas, escrituras y en total dentro de la ventana de tiempo. Al igual que mongostat, la salida se actualiza cada segundo:

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 . . .

Intenta insertar algunos documentos más en la base de datos para ver si la actividad se registra en mongotop. En la terminal de MongoDB, ejecuta el siguiente bucle for; después de hacerlo, observa la ventana de terminal con mongotop en ejecución:

  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. }

Esta vez, la actividad será visible en las estadísticas 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 . . .

Aquí, mongotop muestra que toda la actividad de la base de datos ocurrió en la colección accounts en la base de datos test y que todas las operaciones en la ventana de tiempo han sido operaciones de escritura. Todo esto debería coincidir con la operación del bucle for que ejecutaste.

Al igual que con mongostat, puedes detener mongotop presionando CTRL + C.

Cuando se observa durante la carga máxima, puedes usar mongotop para monitorear cómo se distribuye la actividad de la base de datos entre diferentes colecciones para ayudarte a comprender mejor tu esquema y planificar la escalabilidad. También proporciona información sobre si el uso de una colección es más pesado en lecturas o en escrituras.

Paso 4 — Usando el Perfilador de Base de Datos de MongoDB para Identificar Consultas Lentas

Los cuellos de botella en el rendimiento de la base de datos pueden provenir de muchas fuentes. Aunque escalar la base de datos (ya sea horizontal o verticalmente) suele ser la solución para los cuellos de botella de rendimiento, su causa puede no ser realmente los límites de la base de datos, sino problemas con el esquema o el diseño de consultas.

Si las consultas se ejecutan durante demasiado tiempo, la causa podría ser un uso ineficaz de índices o errores en la consulta misma. Las consultas de larga duración a menudo pasan desapercibidas durante el desarrollo de la aplicación, típicamente porque los conjuntos de datos de prueba son demasiado pequeños o las condiciones son diferentes que en producción.

Podrías potencialmente encontrar al culpable ejecutando manualmente consultas de prueba y revisando cuáles tienen un rendimiento deficiente, aunque esto sería muy tedioso. Afortunadamente, la herramienta de perfilado de la base de datos de MongoDB puede hacerlo automáticamente.

El perfilador de la base de datos de MongoDB puede registrar consultas y estadísticas sobre su ejecución cuando cumplen ciertas condiciones. La más importante de estas condiciones es el tiempo de ejecución de la consulta: si una consulta tarda más de cierto tiempo especificado en ejecutarse, el perfilador automáticamente marcará esa consulta como problemática. Usando el perfilador, puedes identificar qué consultas tienen un rendimiento deficiente y luego enfocarte en solucionar esos problemas particulares.

Antes de usar el perfilador, ejecuta la siguiente consulta. Esta consulta recuperará una de las cuentas que insertaste, aunque no es tan simple como puede parecer a primera vista:

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

El comando recuperará la cuenta exacta que solicitaste:

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

Puede que hayas notado que la consulta no se ejecutó inmediatamente, y tomó a MongoDB un momento o dos encontrar la cuenta. En una aplicación del mundo real, podría haber muchos tipos de consultas que tengan un rendimiento deficiente, y es posible que no notes su bajo rendimiento en la práctica.

Puedes configurar MongoDB para ayudarte a identificar qué consultas tardan más de lo esperado. Para hacerlo, primero habilita el perfilador ejecutando el siguiente comando:

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

El método setProfilingLevel() toma dos argumentos. El primero es el nivel de perfilado, que puede ser 0, 1 o 2:

  • 0 deshabilita el perfilador
  • 1 habilita el perfilador solo en consultas lentas que cumplen la condición
  • 2 habilita el perfilador para todas las consultas.

En este ejemplo, el perfilador analizará las consultas que se ejecuten durante más de 100 milisegundos, según lo definido por el segundo argumento, { slowms: 100 }.

Nota: Usar el perfilador degrada el rendimiento, ya que MongoDB ahora debe analizar las consultas además de ejecutarlas. Debe usarse con moderación al monitorear cuellos de botella de rendimiento.

Es posible ajustar aún más el subconjunto de consultas que el perfilador registrará configurándolo para perfilar solo un cierto porcentaje de consultas o filtrando por tipo de consulta. Para obtener más información sobre cómo tener un mayor control sobre el perfilador, consulte la documentación oficial sobre el tema.

Este método devolverá un mensaje de éxito:

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

Desde ahora, la perfilación de la base de datos estará habilitada y MongoDB monitoreará activamente cada consulta que ejecute para encontrar aquellas que tardan más de 100 milisegundos en completarse.

Pruebe esto ejecutando algunas consultas diferentes. Primero, use el comando count para encontrar el número de documentos en la colección accounts:

  1. db.accounts.count()

Este comando devolverá rápidamente el número de documentos en la colección:

Output
1020000

Luego, intente buscar las primeras tres cuentas bancarias que aparecen en la colección:

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

Nuevamente, la base de datos devolverá los resultados rápidamente:

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 }

Finalmente, ejecute la consulta de búsqueda para la cuenta bancaria específica nuevamente:

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

Esta consulta devolverá el resultado, pero, como antes, tomará un momento o dos más que las operaciones anteriores:

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

El perfilador no produce ninguna salida por sí mismo, aunque la consulta fue visiblemente más lenta. En su lugar, los detalles sobre las operaciones lentas se registran en una colección especial dentro de la base de datos llamada system.profile. Esta colección es una colección limitada que nunca supera 1 MB de tamaño. Eso significa que siempre contendrá una lista de solo las consultas lentas más recientes.

Para recuperar información sobre las consultas identificadas por el perfilador, tienes que consultar la colección system.profile de esta manera:

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

Esta consulta utiliza el método find(), como de costumbre. También incluye una cláusula sort que contiene { "ts" : -1 } como argumento. Esto ordenará el conjunto de resultados con las consultas más recientes primero. Por último, el método pretty() al final mostrará la salida en un formato más legible.

Cada consulta lenta se representa como un documento regular, y system.profile es como cualquier otra colección regular. Esto significa que puedes filtrar los resultados, ordenarlos e incluso usarlos en tuberías de agregación para estrechar aún más o analizar la lista de consultas identificadas por el perfilador.

Observa que el resultado consiste solo en un solo documento. Las otras dos consultas se ejecutaron lo suficientemente rápido como para no activar el perfilador:

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

Esta salida proporciona una serie de detalles sobre la ejecución de la consulta lenta:

  • La clave op muestra qué tipo de operación representa esta información. Aquí, es una consulta, ya que representa una operación en la que se utilizó el find() para recuperar datos de la base de datos.
  • La clave ns indica qué base de datos y colección estuvieron involucradas en la operación. Como muestra la salida, esta operación consultó la colección accounts en la base de datos test.
  • La clave command proporciona más información sobre la consulta en sí. En este caso, el subclave filter contiene el documento completo del filtro. Utilizando la información proveniente de los campos op y command, puedes reconstruir la consulta en cuestión.
  • En el campo millis, encontrarás el tiempo exacto que tomó completar la consulta. En este ejemplo, casi medio segundo.
  • El campo docsExamined proporciona el número de documentos escaneados para devolver el conjunto de resultados.
  • nreturned representa el número de documentos que devolvió la consulta. En este ejemplo, solo se devolvió un documento de más de un millón escaneados.
  • El planSummary muestra el método que MongoDB utilizó para ejecutar la consulta. COLLSCAN corresponde a un escaneo completo de la colección, lo que significa que navegó por cada documento en la colección uno por uno para encontrar la cuenta bancaria coincidente.

Todos juntos, esta información subraya la necesidad de un índice que pueda ayudar a MongoDB a ejecutar esta consulta más rápido. La base de datos tuvo que revisar toda la colección para encontrar un solo documento, como lo indica la gran diferencia entre el número de documentos examinados y devueltos, así como la estrategia de ejecución.

En este ejemplo particular, crear un índice para respaldar consultas que filtren datos basados en el campo number proporcionaría un impulso inmediato al rendimiento de este tipo de consultas. En escenarios reales, las soluciones a las consultas lentas pueden diferir y depender de la consulta exacta que esté causando problemas.

Para finalizar la sesión de perfilado, puedes desactivar el perfilador estableciendo el nivel de perfilado en cero:

  1. db.setProfilingLevel(0)

La operación se llevará a cabo con un mensaje de confirmación:

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

Ahora la base de datos vuelve a la operación normal sin que se realice el perfilado en segundo plano.

Siempre que sospeches que las consultas lentas pueden estar teniendo un impacto negativo en el rendimiento de tu base de datos, puedes utilizar el perfilador de la base de datos para encontrarlas y comprender mejor su estructura y cómo se ejecutan. Con esta información, estarás mejor equipado para ajustarlas y mejorar su rendimiento.

Conclusión

Siguiendo esta guía, aprendiste cómo encontrar las estadísticas del servidor de MongoDB y cómo utilizar herramientas de diagnóstico como mongotop, mongostat, así como el mecanismo de perfilador de base de datos de MongoDB. Puedes usarlos para tener una mejor idea de la carga de trabajo de tu base de datos, determinar qué colecciones son las más activas y si el servidor realiza predominantemente escrituras o lecturas. También puedes identificar consultas lentas que están afectando el rendimiento de MongoDB para reemplazarlas con otras más eficientes.

Estas son solo una selección de herramientas y técnicas que puedes utilizar para monitorear la salud y el rendimiento de tu instalación de MongoDB y actuar en consecuencia. Cada una de estas herramientas se puede configurar y personalizar aún más para proporcionarte una visión más específica del rendimiento del servidor. Te animamos a que estudies la documentación oficial de MongoDB para aprender más sobre técnicas que puedes utilizar para monitorear el rendimiento del servidor y actuar en consecuencia.

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