Saltar al contenido

MongoDB usa demasiada memoria

Hola, hemos encontrado la solución a tu interrogante, desplázate y la verás a continuación.

Solución:

Bien, luego de seguir las pistas dadas por loicmathieu y jstell, y profundizar un poco, estas son las cosas que descubrí sobre MongoDB usando el motor de almacenamiento WiredTiger. Lo pongo aquí si alguien se encuentra con las mismas preguntas.

Los hilos de uso de memoria que mencioné, todos pertenecían a 2012-2014, todos anteriores a WiredTiger y están describiendo el comportamiento del motor de almacenamiento MMAPV1 original que no tiene una caché separada ni soporte para la compresión.

La configuración de la caché de WiredTiger solo controla el tamaño de la memoria utilizada directamente por el motor de almacenamiento de WiredTiger (no la memoria total utilizada por mongod). Muchas otras cosas están potencialmente tomando memoria en una configuración de MongoDB / WiredTiger, como las siguientes:

  • WiredTiger comprime el almacenamiento en disco, pero los datos en la memoria están descomprimidos.

  • WiredTiger por defecto no sincroniza los datos en cada confirmación, por lo que los archivos de registro también están en la RAM, lo que afecta la memoria. También se menciona que para usar la E / S de manera eficiente, WiredTiger fragmenta las solicitudes de E / S (fallas de caché) juntas, que también parecen ocupar algo de RAM (de hecho, las páginas sucias (páginas que han cambiado / actualizado) tienen una lista de actualizaciones en ellos almacenados en una SkipList concurrente).

  • WiredTiger mantiene múltiples versiones de registros en su caché (Control de concurrencia de múltiples versiones, las operaciones de lectura acceden a la última versión comprometida antes de su operación).

  • WiredTiger Mantiene sumas de comprobación de los datos en caché.

  • MongoDB en sí mismo consume memoria para manejar conexiones abiertas, agregaciones, código del lado del servidor, etc..

Teniendo en cuenta estos hechos, confiando en show dbs; no era técnicamente correcto, ya que solo muestra el tamaño comprimido de los conjuntos de datos.

Se pueden usar los siguientes comandos para obtener el tamaño completo del conjunto de datos.

db.getSiblingDB('data_server').stats()
# OR
db.stats()

Este resultado es el siguiente:


    "db" : "data_server",
    "collections" : 11,
    "objects" : 266565289,
    "avgObjSize" : 224.8413545621088,
    "dataSize" : 59934900658, # 60GBs
    "storageSize" : 22959984640,
    "numExtents" : 0,
    "indexes" : 41,
    "indexSize" : 7757348864, # 7.7GBs
    "ok" : 1

Entonces, parece que el tamaño real del conjunto de datos + sus índices están ocupando aproximadamente 68 GB de esa memoria.

Teniendo en cuenta todo esto, creo que el uso de la memoria ahora es bastante esperado, y lo bueno es que está completamente bien limitar el tamaño de la caché de WiredTiger, ya que maneja las operaciones de E / S de manera bastante eficiente (como se describe arriba).

También queda el problema de OOM, para superar este problema, ya que no teníamos suficientes recursos para sacar mongodb, bajamos el oom_score_adj para evitar que OOM elimine procesos importantes por el momento (lo que significa que le dijimos a OOM que no eliminara nuestros procesos deseados).

No creo que tenga un problema aquí con MongoDB, ya que jstell le dijo que MongoDB con WiredTiger usará el 50% de la memoria disponible, por lo que si aumenta la RAM de su servidor, se necesitará más memoria.

Como por qué es más que el tamaño de los índices DB +, tenga en cuenta que WiredTiger comprime la base de datos en el disco y también usa registros de instantáneas para registrar los cambios en los documentos. Entonces, el tamaño real de WiredTiger es el tamaño que usa show dbs * compress_ration + size of snapshot logs. Por lo que es casi imposible saber el tamaño esperado exacto.

Tenga también en cuenta que herramientas como top, ps, htop no mostró la memoria realmente utilizada por la aplicación, consulte esta pregunta de SOW para obtener más detalles: https://stackoverflow.com/questions/131303/how-to-measure-actual-memory-usage-of-an-application- o-proceso

Ahora, volvamos a tu problema. Tiene otras herramientas ejecutándose en el mismo host y un OOM las mata. No estoy familiarizado con Linux OOM, pero ¿estás seguro de que los mata debido a MongoDB o … solo por ellos (tal vez mata a Postgres porque Postgres tomó demasiada memoria)?

De todos modos, como mejor práctica si tiene una gran base de datos Mongo, no la instale en un host compartido con otras bases de datos o tendrá muchas dificultades, en caso de que haya un problema como el que describe aquí, para saber quién realmente causa el problema en el anfitrión.

Docs

Es posible que desee leer las preocupaciones básicas sobre la memoria de MongoDB y también esta breve discusión sobre cómo verificar el uso de la memoria.

Descripción general del uso de memoria

El comando db.serverStatus() (docs) puede proporcionar una descripción general del uso de la memoria, específicamente:

> db.serverStatus().mem
 "bits" : 64, "resident" : 27, "virtual" : 397, "supported" : true 

> db.serverStatus().tcmalloc
... not easy to read! ...

> db.serverStatus().tcmalloc.tcmalloc.formattedString
------------------------------------------------
MALLOC:        3416192 (    3.3 MiB) Bytes in use by application
MALLOC: +      4788224 (    4.6 MiB) Bytes in page heap freelist
MALLOC: +       366816 (    0.3 MiB) Bytes in central cache freelist
...
... a bunch of stats in an easier to read format ...

Cuando tuvimos un problema de RAM, fue porque uno de nuestros índices ocupaba demasiada RAM. Así que aquí mostraré cómo lo rastreamos.

¿Qué tan grandes son sus índices?

db.stats() puede mostrar el tamaño total de todos los índices, pero también podemos obtener información detallada para una sola colección usando db.myCollection.stats()

Por ejemplo, este comando comparar los tamaños de los índices para cada colección:

> db.getCollectionNames().map(name => (totalIndexSize: db.getCollection(name).stats().totalIndexSize, name: name)).sort((a, b) => a.totalIndexSize - b.totalIndexSize).forEach(printjson)
...
 "totalIndexSize" : 696320, "name" : "smallCollection" 
 "totalIndexSize" : 135536640, "name" : "bigCollection" 
 "totalIndexSize" : 382681088, "name" : "hugeCollection" 
 "totalIndexSize" : 511901696, "name" : "massiveCollection" 

Ahora podemos mira los detalles para esa colección masiva, para ver cuáles de sus índices son los más costosos:

> db.massiveCollection.stats().indexSizes

        "_id_" : 230862848,
        "groupId_1_userId_1" : 49971200,
        "createTime_1" : 180301824,
        "orderId_1" : 278528,
        "userId_1" : 50155520

Esto puede darnos una mejor idea de dónde podrían ser posibles los ahorros.

(En este caso, teníamos un índice sobre createTime que era bastante grande, una entrada por documento, y decidimos que podíamos vivir sin él).

Valoraciones y comentarios

Finalizando este artículo puedes encontrar las explicaciones de otros sys admins, tú aún eres capaz insertar el tuyo si lo crees conveniente.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *