MongoDB belegt zu viel Speicher

28

Wir verwenden MongoDB seit einigen Wochen. Der allgemeine Trend, den wir gesehen haben, war, dass Mongodb viel zu viel Speicher belegt (viel mehr als die gesamte Größe seines Datensatzes + der Indizes).

Ich habe diese Frage und diese Frage bereits durchgelesen , aber keine scheint sich mit dem Problem zu befassen, mit dem ich konfrontiert war. Sie erklären tatsächlich, was bereits in der Dokumentation erklärt wurde.

Das Folgende sind die Ergebnisse der Befehle htop und show dbs .

Bildbeschreibung hier eingeben

zeige dbs

Ich weiß, dass mongodb speicherabgebildete E / A-Vorgänge verwendet, sodass das Betriebssystem im Grunde genommen das Zwischenspeichern von Dingen im Speicher handhabt, und mongodb sollte theoretisch seinen zwischengespeicherten Speicher freigeben, wenn ein anderer Prozess freien Speicher anfordert , was wir jedoch gesehen haben, ist dies nicht der Fall.

OOM startet damit, andere wichtige Prozesse wie Postgres, Redis usw. zu beenden. (Um dieses Problem zu beheben, haben wir den RAM auf 183 GB erhöht, was jetzt funktioniert, aber ziemlich teuer ist. Mongo verwendet ~ 87 GB RAM. fast 4X der Größe seines gesamten Datensatzes)

So,

  1. Ist so viel Speicherbedarf wirklich zu erwarten und normal? (Laut Dokumentation verwendet WiredTiger höchstens ~ 60% des Arbeitsspeichers für den Cache. Hat der WiredTiger unter Berücksichtigung der Datenmenge überhaupt genug Daten, um 86 GB RAM aufnehmen zu können?)
  2. Auch wenn die Speichernutzung erwartet wird, warum lässt mongo den zugewiesenen Speicher nicht los, falls ein anderer Prozess beginnt, mehr Speicher anzufordern? Verschiedene andere laufende Prozesse, einschließlich Mongodb selbst, wurden ständig von Linux-oom abgebrochen, bevor wir den Arbeitsspeicher vergrößerten und das System dadurch völlig instabil wurde.

Vielen Dank !

SpiXel
quelle
4
Vielleicht können einige der Präsentationen zu Interna von WiredTiger, wie mongodb.com/presentations/… , etwas Licht ins Dunkel bringen. Ich gehe davon aus, dass die Standardauslastung von 50% des physischen Arbeitsspeichers nur eine Vermutung dessen ist, was auf einem dedizierten MongoDB-Host wahrscheinlich erforderlich ist, und viele müssen dies ändern. FWIW, ich glaube nicht, dass das Setzen von cacheSizeGB das Mongo "einschränkt" - die Option ist vorhanden, damit Sie die Kontrolle über Bereitstellungen haben. Um festzustellen, wie viel Speicher der Mongo für den Cache "benötigt", müssen Sie die Server-Cache-Statistiken unter der erwarteten Serverauslastung überwachen.

Antworten:

23

Okay, nachdem ich den Hinweisen von Loicmathieu und Jstell gefolgt und ein wenig nachgegangen bin, habe ich mithilfe der WiredTiger-Speicher-Engine Folgendes über MongoDB herausgefunden. Ich schreibe es hier, wenn jemand die gleichen Fragen hat.

Die Speicherauslastungsthreads, die ich erwähnt habe, gehörten alle zu 2012-2014, waren alle WiredTiger vor dem Datum und beschreiben das Verhalten der ursprünglichen MMAPV1-Speicher-Engine, die keinen separaten Cache oder keine Unterstützung für die Komprimierung hat.

Die WiredTiger- Cache-Einstellungen steuern nur die Größe des Speichers, der direkt von der WiredTiger-Speicher-Engine verwendet wird (nicht den von Mongod verwendeten Gesamtspeicher). In einer MongoDB / WiredTiger-Konfiguration beanspruchen möglicherweise viele andere Dinge Speicher, z. B. die folgenden:

  • WiredTiger komprimiert den Festplattenspeicher, die Daten im Speicher werden jedoch nicht komprimiert.

  • WiredTiger synchronisiert die Daten nicht standardmäßig bei jedem Commit , daher befinden sich die Protokolldateien auch im RAM, was den Arbeitsspeicher belastet . Es wird auch erwähnt, dass WiredTiger zur effizienten Nutzung von E / A-Vorgängen E / A-Anforderungen (Cache-Fehlschläge) zusammenfasst, was ebenfalls RAM-Speicher beansprucht auf ihnen in einer Concurrent SkipList gespeichert ).

  • WiredTiger speichert mehrere Versionen von Datensätzen im Cache (Multi Version Concurrency Control, Leseoperationen greifen auf die letzte festgeschriebene Version vor ihrer Operation zu).

  • WiredTiger Hält die Prüfsummen der Daten im Cache.

  • MongoDB selbst verbraucht Speicher, um offene Verbindungen, Aggregationen, serverseitigen Code usw. zu verarbeiten .

In Anbetracht dieser Tatsachen show dbs;war es technisch nicht korrekt , sich auf zu verlassen , da nur die komprimierte Größe der Datensätze angezeigt wird.

Die folgenden Befehle können verwendet werden, um die vollständige Datenmenge abzurufen.

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

Dies führt zu folgenden Ergebnissen:

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

Es scheint also, dass die tatsächliche Datenmenge + ihre Indizes ungefähr 68 GB dieses Speichers beanspruchen.

In Anbetracht all dieser Faktoren ist die Speicherauslastung nun ziemlich hoch, und zum Teil ist es völlig in Ordnung, die Größe des WiredTiger-Caches zu begrenzen, da E / A-Vorgänge sehr effizient ausgeführt werden (wie oben beschrieben).

Es bleibt auch das Problem von OOM bestehen, um dieses Problem zu lösen, da wir nicht über genügend Ressourcen zum Entfernen von Mongodb verfügten. Daher haben wir oom_score_adj gesenkt , um zu verhindern, dass OOM wichtige Prozesse vorübergehend beendet gewünschte Prozesse ).

SpiXel
quelle
Wir haben ein ähnliches Problem. MongoDB frisst weiterhin RAM. Ähnliche Proportionen. War die oom_score_adj Lösung die beste Lösung, die Sie finden konnten?
Hartator
@Hartator Nun, wir haben die Cache-Größe von wiredtiger verringert, uns mehr um die Verwaltung unserer Indizes und der Indexierungsrichtlinie gekümmert und schließlich oom_score_adj für die Dinge, die uns wichtig waren, verringert, das ist alles, was wir sowieso tun können.
SpiXel
4

Ich glaube nicht, dass Sie hier ein Problem mit MongoDB haben, da laut Jstell MongoDB mit WiredTiger 50% des verfügbaren Arbeitsspeichers beansprucht. Wenn Sie also den Arbeitsspeicher Ihres Servers erhöhen, wird mehr Arbeitsspeicher benötigt.

Denken Sie daran, dass WiredTiger nicht nur die Größe von DB + -Indizes überschreitet, sondern auch die Datenbank auf der Festplatte komprimiert und Snapshot-Protokolle verwendet, um Dokumentänderungen aufzuzeichnen. Die tatsächliche Größe des WiredTigers entspricht also der Größe, die unter Verwendung von show dbs * compression_ration + Größe der Snapshot-Protokolle ermittelt wurde. So ist es fast unmöglich, die genaue erwartete Größe zu kennen.

Denken Sie auch daran , dass Werkzeuge wie top, ps, htophat die Erinnerung nicht angezeigt werden wirklich von der Anwendung verwendet, refere auf diese SOW Frage nach Details: https://stackoverflow.com/questions/131303/how-to-measure-actual-memory -gebrauch-einer-anwendung-oder-prozess

Nun zurück zu Ihrem Problem. Sie haben andere Tools, die auf demselben Host ausgeführt werden, und ein OOM beendet sie. Ich bin nicht mit Linux OOM vertraut, aber sind Sie sicher, dass es diese wegen MongoDB oder .. nur wegen ihnen tötet (vielleicht tötet es Postgres, weil Postgres zu viel Speicherplatz in Anspruch genommen hat).

Wie auch immer, als Best Practice, wenn Sie eine große Mongo-Datenbank haben, installieren Sie sie nicht auf einem Host, der mit anderen Datenbanken geteilt wird, oder Sie werden eine Menge Schwierigkeiten haben, falls es ein Problem wie das hier beschriebene gibt die wirklich das Problem auf dem Host verursachen.

loicmathieu
quelle
4

Docs

Sie möchten vielleicht grundlegende Speicherprobleme für MongoDB und auch diese kurze Diskussion über das Überprüfen der Speichernutzung lesen .

Übersicht über die Speichernutzung

Der Befehl db.serverStatus()( docs ) bietet einen Überblick über die Speichernutzung, insbesondere:

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

Wie groß sind Ihre Indizes?

db.stats() kann die Gesamtgröße aller Indizes anzeigen, aber wir können mit auch detaillierte Informationen für eine einzelne Sammlung abrufen db.myCollection.stats()

Mit diesem Befehl werden beispielsweise die Größen der Indizes für jede Sammlung verglichen :

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

Jetzt können wir uns die Details für diese umfangreiche Sammlung ansehen , um herauszufinden, welche ihrer Indizes die teuersten sind:

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

Dies kann uns eine bessere Vorstellung davon geben, wo Einsparungen möglich sind.

(In diesem Fall hatten wir einen Index, createTimeder ziemlich umfangreich war - ein Eintrag pro Dokument - und wir entschieden, dass wir ohne ihn leben könnten.)

joeytwiddle
quelle
Haben Indizes hohe Speicherkosten?
Mathias Lykkegaard Lorenzen
@MathiasLykkegaardLorenzen Dies hängt von der Anzahl der eindeutigen Werte für das von Ihnen indizierte Feld im Verhältnis zum RAM Ihres Servers ab. In unserem Fall war der createTimeIndex problematisch, da er für jedes einzelne Dokument eindeutig war und diese Sammlung riesig war. Das Indizieren der anderen Felder war in Ordnung, da weniger eindeutige Werte vorhanden waren (die Werte wurden in Clustern zusammengefasst).
Joeytwiddle