it-swarm.com.de

MongoDB verwendet zu viel Speicher

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

Ich habe bereits diese Frage und diese Frage durchgelesen, aber keiner scheint das Problem anzusprechen, 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.

(enter image description here

(show dbs

Ich weiß, dass Mongodb speicherabgebildete E/A verwendet, daher behandelt das Betriebssystem im Grunde genommen das Zwischenspeichern von Dingen im Speicher, und Mongodb sollte theoretisch seinen zwischengespeicherten Speicher loslassen, wenn ein anderer Prozess freien Speicher anfordert , aber von dem, was wir haben gesehen, tut es nicht.

OOM startet und beendet andere wichtige Prozesse, z. postgres, redis usw. (Wie zu sehen ist, haben wir zur Überwindung dieses Problems das RAM auf 183 GB erhöht, was jetzt funktioniert, aber ziemlich teuer ist. Mongos verwenden ~ 87 GB RAM, fast das Vierfache des RAM Größe des gesamten Datensatzes)

Damit,

  1. Wird so viel Speicher wirklich erwartet und ist normal? (Gemäß der Dokumentation verwendet WiredTiger höchstens ~ 60% von RAM für seinen Cache. In Anbetracht der Größe des Datasets sind jedoch sogar genügend Daten vorhanden, um 86 GB RAM aufnehmen zu können ?)
  2. Selbst wenn die Speichernutzung erwartet wird, warum lässt Mongo den zugewiesenen Speicher nicht los, falls ein anderer Prozess anfängt, mehr Speicher anzufordern? Verschiedene andere laufende Prozesse wurden ständig von Linux OOM beendet, einschließlich Mongodb selbst, bevor wir das RAM erhöhten und das System völlig instabil machte.

Vielen Dank !

29
SpiXel

Okay, nachdem ich den Hinweisen von Loicmathieu und Jstell gefolgt bin und sie ein wenig ausgegraben habe, habe ich diese Dinge über MongoDB mithilfe der WiredTiger-Speicher-Engine herausgefunden. Ich stelle es hier ein, wenn jemand auf die gleichen Fragen gestoßen ist.

Die von mir erwähnten Threads zur Speichernutzung gehörten alle zu 2012-2014 , alle vor dem Datum WiredTiger und beschreiben das Verhalten der ursprünglichen MMAPV1-Speicher-Engine, die dies nicht tut Es gibt keinen separaten Cache oder Unterstützung für die Komprimierung.

Der WiredTiger Cache-Einstellungen steuert nur die Größe des Speichers, der direkt von der WiredTiger-Speicher-Engine verwendet wird (nicht den von mongod verwendeten Gesamtspeicher). Viele andere Dinge beanspruchen möglicherweise Speicher in einer MongoDB/WiredTiger-Konfiguration, wie zum Beispiel die folgenden:

  • WiredTiger komprimiert den Festplattenspeicher, aber die Daten im Speicher sind nicht komprimiert.

  • WiredTiger synchronisiert die Daten standardmäßig nicht bei jedem Commit , daher befinden sich die Protokolldateien auch in RAM, das seine nimmt Es wird auch erwähnt, dass WiredTiger E/A-Anforderungen (Cache-Fehler) zusammenfasst, um E/A effizient zu nutzen. Dies scheint auch einige RAM (Tatsächlich schmutzige Seiten) zu erfordern (Seiten, die geändert/aktualisiert wurden) haben eine Liste von Aktualisierungen in einer Concurrent SkipList ).

  • WiredTiger speichert mehrere Versionen von Datensätzen in seinem Cache (Multi Version Concurrency Control, Lesevorgänge greifen auf die letzte festgeschriebene Version vor ihrem Vorgang zu).

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

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

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

Die folgenden Befehle können verwendet werden, um die vollständige Datensatzgröße zu erhalten.

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

Dieses Ergebnis ist das folgende:

{
    "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 Größe des Datensatzes + seine Indizes ungefähr 68 GB dieses Speichers beanspruchen.

In Anbetracht all dessen denke ich, dass die Speichernutzung jetzt ziemlich erwartet wird. Ein guter Teil ist, dass es völlig in Ordnung ist, die WiredTiger-Cache-Größe zu begrenzen, da sie E/A-Operationen ziemlich effizient abwickelt (wie oben beschrieben).

Es bleibt auch das Problem von OOM, um dieses Problem zu lösen, da wir nicht genügend Ressourcen hatten, um Mongodb auszuschalten, haben wir den oom_score_adj gesenkt, um dies zu verhindern OOM daran, wichtige Prozesse vorerst zu beenden (was bedeutet, wir haben gesagt OOM, unsere gewünschten Prozesse nicht zu beenden ).

23
SpiXel

Docs

Vielleicht möchten Sie grundlegende Speicherprobleme für MongoDB und auch diese kurze Diskussion über die Überprüfung der Speichernutzung lesen.

Übersicht über die Speichernutzung

Der Befehl db.serverStatus() ( docs ) kann einen Überblick über die Speichernutzung geben, 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 auch detaillierte Informationen für eine einzelne Sammlung mit db.myCollection.stats() abrufen

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 die Details für diese umfangreiche Sammlung betrachten, um festzustellen, 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 sein könnten.

(In diesem Fall hatten wir einen Index über createTime, der ziemlich groß war - ein Eintrag pro Dokument - und wir beschlossen, ohne ihn zu leben.)

4
joeytwiddle

Ich glaube nicht, dass Sie hier ein Problem mit MongoDB haben, da jstell Ihnen sagte, dass MongoDB mit WiredTiger 50% des verfügbaren Speichers verbraucht. Wenn Sie also die RAM Ihres Servers) erhöhen, wird mehr Speicher benötigt .

Beachten Sie, dass WiredTiger die Datenbank auf der Festplatte komprimiert und Snapshot-Protokolle zum Aufzeichnen von Dokumentänderungen verwendet, da dies mehr als die Größe von DB + -Indizes ist. Die tatsächliche Größe des WiredTigers entspricht also der Größe mit show dbs * compress_ration + size der Snapshot-Protokolle. Es ist also fast unmöglich, die genaue erwartete Größe zu kennen.

Beachten Sie auch, dass Tools wie top, ps, htop den von der Anwendung tatsächlich verwendeten Speicher nicht angezeigt haben. Weitere Informationen finden Sie in dieser SOW-Frage: https://stackoverflow.com/questions/131303/how-to-measure-actual-memory-usage-of-an-application-or-process

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 Speicher benötigt).

Als bewährte Methode, wenn Sie eine große Mongo-Datenbank haben, installieren Sie diese nicht auf einem Host, der mit anderen Datenbanken geteilt wird, da Sie sonst viele Schwierigkeiten haben, falls es ein Problem wie das hier beschriebene gibt die das Problem wirklich auf dem Host verursachen.

4
loicmathieu