MongoDB utilisant trop de mémoire


28

Nous utilisons MongoDB depuis plusieurs semaines maintenant, la tendance générale que nous avons constatée est que mongodb utilise beaucoup trop de mémoire (bien plus que la taille totale de son ensemble de données + index).

J'ai déjà lu cette question et cette question , mais aucun ne semble résoudre le problème que j'ai rencontré, ils expliquent en fait ce qui est déjà expliqué dans la documentation.

Voici les résultats des commandes htop et show dbs .

entrez la description de l'image ici

montrer dbs

Je sais que mongodb utilise des E / S mappées en mémoire, donc fondamentalement, le système d'exploitation gère les éléments de mise en cache dans la mémoire, et mongodb devrait théoriquement lâcher sa mémoire en cache lorsqu'un autre processus demande de la mémoire libre , mais d'après ce que nous avons vu, ce n'est pas le cas.

Le MOO démarre et tue d'autres processus importants, par exemple les postgres, les redis, etc. (Comme on peut le voir, pour surmonter ce problème, nous avons augmenté la RAM à 183 Go, ce qui fonctionne maintenant mais est assez cher. Mongo utilise ~ 87 Go de RAM, près de 4 fois la taille de l'ensemble de ses données)

Alors,

  1. Cette utilisation de la mémoire est-elle vraiment attendue et normale? (Selon la documentation, WiredTiger utilise au maximum ~ 60% de RAM pour son cache, mais compte tenu de la taille de l'ensemble de données, dispose-t-il même de suffisamment de données pour pouvoir prendre 86 Go de RAM?)
  2. Même si l'utilisation de la mémoire est attendue, pourquoi mongo ne lâche-t-il pas sa mémoire allouée au cas où un autre processus commencerait à demander plus de mémoire? Divers autres processus en cours d'exécution étaient constamment tués par linux oom, y compris mongodb lui-même, avant d'augmenter la RAM et de rendre le système totalement instable.

Merci !


4
Peut-être que certaines des présentations sur les éléments internes de WiredTiger, telles que mongodb.com/presentations/… , peuvent apporter un éclairage. Je m'attends à ce que l'utilisation par défaut de 50% de la RAM physique soit juste une estimation de ce qui est probablement requis sur un hôte MongoDB dédié, et beaucoup devront le changer. FWIW, je ne crois pas que la définition du cacheSizeGB mongo "limite" - l'option est là pour que vous ayez le contrôle sur les déploiements. Pour déterminer la quantité de mémoire dont le mongo a besoin pour le cache, vous devez surveiller les statistiques du cache du serveur sous la charge attendue du serveur.

Réponses:


23

D'accord, donc après avoir suivi les indices donnés par loicmathieu et jstell, et avoir creusé un peu, ce sont les choses que j'ai découvertes sur MongoDB en utilisant le moteur de stockage WiredTiger. Je le mets ici si quelqu'un a rencontré les mêmes questions.

Les threads d'utilisation de la mémoire que j'ai mentionnés appartenaient tous à 2012-2014, tous antérieurs à WiredTiger et décrivent le comportement du moteur de stockage MMAPV1 d'origine qui n'a pas de cache séparé ni de support pour la compression.

Les paramètres du cache WiredTiger contrôlent uniquement la taille de la mémoire directement utilisée par le moteur de stockage WiredTiger (pas la mémoire totale utilisée par mongod). Beaucoup d'autres choses prennent potentiellement de la mémoire dans une configuration MongoDB / WiredTiger, comme les suivantes:

  • WiredTiger compresse le stockage sur disque, mais les données en mémoire ne sont pas compressées.

  • Par défaut, WiredTiger ne synchronise pas les données sur chaque commit , donc les fichiers journaux sont également en RAM, ce qui pèse lourdement sur la mémoire. Il est également mentionné que pour utiliser efficacement les E / S, WiredTiger regroupe les demandes d'E / S (cache manquant), ce qui semble également prendre de la RAM (En fait, les pages sales (pages qui ont changé / mis à jour) ont une liste de mises à jour stockées dans une SkipList simultanée ).

  • WiredTiger conserve plusieurs versions d'enregistrements dans son cache (Multi Version Concurrency Control, les opérations de lecture accèdent à la dernière version validée avant leur opération).

  • WiredTiger Conserve les sommes de contrôle des données dans le cache.

  • MongoDB se consomme de la mémoire pour gérer les connexions ouvertes, agrégations, code Serverside et etc .

Compte tenu de ces faits, s'appuyer sur show dbs;n'était pas techniquement correct, car il ne montre que la taille compressée des ensembles de données.

Les commandes suivantes peuvent être utilisées afin d'obtenir la taille complète du jeu de données.

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

Ces résultats sont les suivants:

{
    "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
}

Il semble donc que la taille réelle du jeu de données + ses index prennent environ 68 Go de cette mémoire.

Compte tenu de tout cela, je suppose que l'utilisation de la mémoire est maintenant assez attendue, bonne partie étant qu'il est tout à fait correct de limiter la taille du cache WiredTiger, car il gère les opérations d'E / S assez efficacement (comme décrit ci-dessus).

Il reste également le problème de MOO, pour surmonter ce problème, puisque nous n'avions pas suffisamment de ressources pour supprimer mongodb, nous avons réduit le oom_score_adj pour empêcher le MOO de tuer des processus importants pour le moment (ce qui signifie que nous avons dit au MOO de ne pas tuer notre processus souhaités ).


Nous avons un problème similaire. MongoDB continue de manger de la RAM. Proportions similaires. La oom_score_adj solution était-elle la meilleure chose que vous ayez trouvée?
Hartator

@Hartator Eh bien, nous avons diminué cacheSize de wiredtiger, déployé plus d'efforts sur la gestion de nos index et de la politique d'indexation, puis finalement, diminué oom_score_adj pour les choses dont nous nous occupions, c'est, je suppose, tout ce qui peut être fait de toute façon.
SpiXel

4

Je ne pense pas que vous ayez un problème avec MongoDB, car jstell vous a dit que MongoDB avec WiredTiger utiliserait 50% de la mémoire disponible, donc si vous augmentez la RAM de votre serveur, cela prendra plus de mémoire.

Comme c'est plus que la taille des index DB +, gardez à l'esprit que WiredTiger compresse la base de données sur le disque et utilise également des journaux d'instantanés pour enregistrer les modifications de document. Ainsi, la taille réelle du WiredTiger est la taille utilisant show dbs * compression_ration + taille des journaux d'instantanés. Il est donc presque impossible de connaître la taille exacte attendue.

Gardez à l' esprit que les outils comme top, ps, htopn'affichait pas la mémoire réellement utilisée par l'application, refere à cette question SOW pour plus de détails: /programming/131303/how-to-measure-actual-memory -utilisation-d'une-application-ou-processus

Maintenant, revenons à votre problème. Vous disposez d'autres outils exécutés sur le même hôte et un MOO les tue. Je ne connais pas Linux OOM mais êtes-vous sûr qu'il tue ceux-ci à cause de MongoDB ou .. juste à cause d'eux (peut-être qu'il tue Postgres parce que Postgres a pris trop de mémoire).

Quoi qu'il en soit, comme meilleure pratique si vous avez une grande base de données Mongo, ne l'installez pas dans un hôte partagé avec d'autres bases de données ou vous aurez beaucoup de difficultés, au cas où il y aurait un problème comme celui que vous décrivez ici, à savoir qui causent vraiment le problème sur l'hôte.


4

Documents

Vous aimerez peut-être lire les problèmes de mémoire de base pour MongoDB et également cette brève discussion sur la vérification de l'utilisation de la mémoire .

Présentation de l'utilisation de la mémoire

La commande db.serverStatus()( docs ) peut fournir un aperçu de l'utilisation de la mémoire, en particulier:

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

Quelle est la taille de vos index?

db.stats() peut afficher la taille totale de tous les index, mais nous pouvons également obtenir des informations détaillées pour une seule collection en utilisant db.myCollection.stats()

Par exemple, cette commande comparera les tailles des index pour chaque collection :

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

Maintenant, nous pouvons regarder les détails de cette collection massive, pour voir lesquels de ses index sont les plus coûteux:

> db.massiveCollection.stats().indexSizes
{
        "_id_" : 230862848,
        "groupId_1_userId_1" : 49971200,
        "createTime_1" : 180301824,
        "orderId_1" : 278528,
        "userId_1" : 50155520
}

Cela peut nous donner une meilleure idée des économies possibles.

(Dans ce cas, nous avions un index sur createTimelequel était assez énorme - une entrée par document - et nous avons décidé que nous pouvions vivre sans.)


Les index ont-ils un gros coût de mémoire?
Mathias Lykkegaard Lorenzen

@MathiasLykkegaardLorenzen Cela dépend du nombre de valeurs uniques pour le champ que vous avez indexé, par rapport à la RAM de votre serveur. Dans notre cas, l' createTimeindex était problématique car il était unique pour chaque document et cette collection était énorme. L'indexation des autres champs était correcte, car il y avait moins de valeurs uniques (les valeurs étaient regroupées).
joeytwiddle
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.