In meinem vorherigen Blog How to use MongoDB Data Modeling to Improve Throughput Operations haben wir die beiden wichtigsten Ansätze für Datenmodellierungsbeziehungen besprochen, nämlich Einbettung und Referenzierung. Die Skalierbarkeit von MongoDB hängt stark von seiner Architektur und insbesondere von der Datenmodellierung ab. Bei der Konzeption eines NoSQL-DBM gilt es neben einer geringen Anzahl von Collections zwecks einfacher Wartung vor allem auf schemalose Dokumente zu achten. Gute Datenintegrität, Datenvalidierung durch einige definierte Regeln vor der Speicherung wird empfohlen. Eine Datenbankarchitektur und ein Design sollten normalisiert und in mehrere kleine Sammlungen zerlegt werden, um Datenwiederholungen zu vermeiden, die Datenintegrität zu verbessern und Abrufmuster zu vereinfachen. Damit können Sie die Datenkonsistenz, Atomizität, Dauerhaftigkeit und Integrität Ihrer Datenbank verbessern.
Die Datenmodellierung ist kein nachträgliches Unterfangen in einer Anwendungsentwicklungsphase, sondern eine erste Überlegung, da viele Anwendungsfacetten tatsächlich während der Datenmodellierungsphase realisiert werden. In diesem Artikel werden wir diskutieren, welche Faktoren bei der Datenmodellierung berücksichtigt werden müssen und wie sie sich auf die Leistung einer Datenbank im Allgemeinen auswirken.
Oft müssen Sie einen Cluster Ihrer Datenbank bereitstellen, um die Datenverfügbarkeit zu erhöhen. Mit einem gut gestalteten Datenmodell können Sie Aktivitäten effektiver auf einen Sharded-Cluster verteilen und somit die Durchsatzoperationen reduzieren, die auf eine einzelne Mongod-Instanz abzielen. Zu den wichtigsten Faktoren, die bei der Datenmodellierung zu berücksichtigen sind, gehören:
- Skalierbarkeit
- Atomizität
- Leistung und Datennutzung
- Sharding
- Indizierung
- Speicheroptimierung
- Dokumentstruktur und Wachstum
- Datenlebenszyklus
1. Skalierbarkeit
Dies ist eine Erhöhung der Arbeitslast einer Anwendung, die durch erhöhten Datenverkehr verursacht wird. Viele Anwendungen haben immer eine Erwartung in der Zunahme der Anzahl ihrer Benutzer. Wenn so viele Benutzer von einer einzigen Datenbankinstanz bedient werden, entspricht die Leistung nicht immer den Erwartungen. Als Datenbankmanager haben Sie daher den Auftrag, dieses DBM so zu gestalten, dass Sammlungen und Datenentitäten basierend auf den gegenwärtigen und zukünftigen Anforderungen der Anwendung modelliert werden. Die Datenbankstruktur sollte im Allgemeinen vorzeigbar sein, um den Prozess der Replikation und des Shardings zu vereinfachen. Wenn Sie mehr Shards haben, werden die Schreibvorgänge auf diese Shards verteilt, sodass jede Datenaktualisierung innerhalb des Shards erfolgt, der diese Daten enthält, anstatt in einem einzigen großen Datensatz nachzuschlagen, um eine Aktualisierung vorzunehmen.
2. Atomizität
Dies bezieht sich auf den Erfolg oder Misserfolg eines Vorgangs als einzelne Einheit. Beispielsweise könnten Sie eine Leseoperation haben, die nach dem Abrufen des Ergebnisses eine Sortieroperation beinhaltet. Wenn die Sortieroperation nicht richtig gehandhabt wird, geht die gesamte Operation daher nicht zur nächsten Stufe über.
Atomare Transaktionen sind eine Reihe von Operationen, die weder teilbar noch reduzierbar sind und daher als einzelne Einheiten auftreten oder als einzelne Operationen fehlschlagen. MongoDB-Versionen vor 4.0 unterstützen Schreibvorgänge als atomare Prozesse auf einer einzelnen Dokumentebene. Mit der Version 4.0 kann man nun Multi-Document-Transaktionen implementieren. Ein Datenmodell, das atomare Operationen verbessert, hat in der Regel eine hervorragende Latenzleistung. Latenz ist einfach die Dauer, innerhalb derer eine Operationsanforderung gesendet und eine Antwort von der Datenbank zurückgegeben wird. Kurz gesagt, es ist einfach, Daten zu aktualisieren, die in ein einzelnes Dokument eingebettet sind, anstatt in eines, auf das verwiesen wird.
Betrachten wir zum Beispiel den folgenden Datensatz
{
childId : "535523",
studentName : "James Karanja",
parentPhone : 704251068,
age : 12,
settings : {
location : "Embassy",
address : "420 01",
bus : "KAZ 450G",
distance : "4"
}
}
Wenn wir das Alter aktualisieren möchten, indem wir es um 1 erhöhen und den Standort in London ändern, könnten wir Folgendes tun:
db.getCollection(‘students’).update({childId: 535523},{$set:{'settings.location':'London'}, $inc:{age:1}}).
Wenn zum Beispiel die $set-Operation fehlschlägt, wird automatisch die $inc-Operation nicht implementiert und im Allgemeinen schlägt die gesamte Operation fehl.
Betrachten wir andererseits referenzierte Daten so, dass es zwei Sammlungen gibt, eine für Schüler und die andere für Einstellungen.
Studentensammlung
{
childId : "535523",
studentName : "James Karanja",
parentPhone : 704251068,
age : 12
}
Sammlung von Einstellungen
{
childId : "535523",
location : "Embassy",
address : "420 01",
bus : "KAZ 450G",
distance : "4"
}
In diesem Fall können Sie die Werte für Alter und Ort mit separaten Schreibvorgängen aktualisieren, z. B.
db.getCollection(‘students’).update({childId: 535523},{$inc:{age:1}})
db.getCollection('settings’).update({childId: 535523 } , {$set: { 'settings.location':'London'}})
Wenn einer der Vorgänge fehlschlägt, wirkt sich dies nicht unbedingt auf den anderen aus, da sie als unterschiedliche Einheiten ausgeführt werden.
Transaktionen für mehrere Dokumente
Mit MongoDB Version 4.0 können Sie jetzt mehrere Dokumententransaktionen für Replikatsätze durchführen. Dies verbessert die Leistung, da die Operationen zur schnellen Verarbeitung an eine Reihe von Sammlungen, Datenbanken und Dokumenten ausgegeben werden. Wenn eine Transaktion festgeschrieben wurde, werden die Daten gespeichert, während wenn etwas schief geht und eine Transaktion fehlschlägt, die vorgenommenen Änderungen verworfen und die Transaktion im Allgemeinen abgebrochen wird. Während der Transaktion findet keine Aktualisierung der Replikatsätze statt, da die Operation nur außerhalb sichtbar ist, wenn die Transaktion vollständig festgeschrieben ist.
So sehr Sie mehrere Dokumente in mehreren Transaktionen aktualisieren können, ist dies im Vergleich zum Schreiben eines einzelnen Dokuments mit einem Rückschlag der reduzierten Leistung verbunden. Außerdem wird dieser Ansatz nur für die WiredTiger-Speicher-Engine unterstützt und ist daher ein Nachteil für die In-Memory- und MMAPv1-Speicher-Engines.
3. Leistung und Datennutzung
Anwendungen sind unterschiedlich gestaltet, um unterschiedliche Zwecke zu erfüllen. Es gibt einige, die nur für die aktuellen Daten dienen, wie Wetternachrichten-Anwendungen. Je nach Struktur einer Anwendung sollte man in der Lage sein, eine entsprechende optimale Datenbank zu entwerfen, um den erforderlichen Anwendungsfall zu bedienen. Wenn Sie beispielsweise eine Anwendung entwickeln, die die neuesten Daten aus der Datenbank abruft, ist die Verwendung einer begrenzten Sammlung die beste Option. Eine begrenzte Sammlung verbessert den Betrieb mit hohem Durchsatz genau wie ein Puffer, so dass, wenn der zugewiesene Speicherplatz ausgenutzt wird, die ältesten Dokumente überschrieben werden und die Dokumente in der Reihenfolge abgerufen werden können, in der sie eingefügt wurden. In Anbetracht des Abrufs der Einfügereihenfolge besteht keine Notwendigkeit, eine Indexierung zu verwenden, und das Fehlen eines Index-Overheads wird den Schreibdurchsatz gleichermaßen verbessern. Bei einer begrenzten Sammlung sind die zugehörigen Daten ziemlich klein, da sie für einige Zeit im RAM gehalten werden können. Temporäre Daten werden in diesem Fall im Cache gespeichert, der eher gelesen als geschrieben wird, wodurch der Lesevorgang ziemlich schnell wird. Die begrenzte Sammlung hat jedoch einige Nachteile, z. B. können Sie ein Dokument nicht löschen, es sei denn, Sie löschen die gesamte Sammlung, jede Änderung der Größe eines Dokuments führt zum Scheitern der Operation und schließlich ist es nicht möglich, eine begrenzte Sammlung zu fragmentieren.
Je nach Nutzungsbedarf werden unterschiedliche Facetten in die Datenmodellierung einer Datenbank integriert. Wie wir gesehen haben, sind Berichtsanwendungen tendenziell leseintensiver, daher sollte das Design so gestaltet sein, dass der Lesedurchsatz verbessert wird.
4. Sharding
Die Leistung durch horizontale Skalierung kann durch Sharding verbessert werden, da die Lese- und Schreiblasten auf die Clustermitglieder verteilt werden. Die Bereitstellung eines Shard-Clusters neigt dazu, die Datenbank in mehrere kleine Sammlungen mit verteilten Dokumenten zu partitionieren, die von einem Shard-Schlüssel abhängen. Sie sollten einen geeigneten Shard-Schlüssel auswählen, der neben der Erhöhung der Schreibkapazität die Abfrageisolierung verhindern kann. Eine bessere Auswahl umfasst im Allgemeinen ein Feld, das in allen Dokumenten innerhalb der Zielsammlung vorhanden ist. Beim Sharding wird der Speicherplatz erhöht, da mit zunehmender Datenmenge mehr Shards eingerichtet werden, um eine Teilmenge dieses Clusters aufzunehmen.
5. Indizierung
Die Indizierung ist einer der besten Ansätze zur Verbesserung der Schreibarbeitslast, insbesondere wenn die Felder in allen Dokumenten vorkommen. Bei der Indizierung sollte berücksichtigt werden, dass jeder Index 8 KB Speicherplatz benötigt. Wenn der Index aktiv ist, verbraucht er außerdem etwas Speicherplatz und Arbeitsspeicher und sollte daher für die Kapazitätsplanung nachverfolgt werden.
Multiplenines Become a MongoDB DBA – Bringing MongoDB to ProductionErfahren Sie, was Sie wissen müssen, um MongoDBDownload for Free bereitzustellen, zu überwachen, zu verwalten und zu skalieren6. Speicheroptimierung
Viele kleine Dokumente innerhalb einer Sammlung nehmen tendenziell mehr Platz ein, als wenn Sie einige wenige Dokumente mit untergeordneten eingebetteten Dokumenten haben. Bei der Modellierung sollte man daher die zusammengehörigen Daten vor der Speicherung gruppieren. Bei wenigen Dokumenten kann eine Datenbankoperation mit wenigen Abfragen durchgeführt werden, wodurch der zufällige Plattenzugriff reduziert wird und es weniger zugehörige Schlüsseleinträge im entsprechenden Index gibt. Überlegungen in diesem Fall sind daher:Verwenden Sie die Einbettung, um weniger Dokumente zu haben, was wiederum den Overhead pro Dokument reduziert. Verwenden Sie kürzere Feldnamen, wenn weniger Felder in einer Sammlung enthalten sind, um den Dokumenten-Overhead nicht erheblich zu machen. Kürzere Feldnamen reduzieren die Aussagekraft .d.h.
{ Lname : "Briston", score : 5.9 }
spart 9 Byte pro Dokument anstatt
zu verwenden{ last_name : "Briston", high_score: 5.9 }
Verwenden Sie explizit das Feld _id. Standardmäßig fügen MongoDB-Clients jedem Dokument ein _id-Feld hinzu, indem sie diesem Feld eine eindeutige 12-Byte-ObjectId zuweisen. Außerdem wird das Feld _id indiziert. Wenn die Dokumente ziemlich klein sind, wird dieses Szenario einen erheblichen Platzbedarf in der gesamten Dokumentenanzahl einnehmen. Zur Speicheroptimierung dürfen Sie den Wert für das Feld _id explizit angeben, wenn Sie Dokumente in eine Sammlung einfügen. Stellen Sie jedoch sicher, dass der Wert eindeutig identifiziert wird, da er als Primärschlüssel für Dokumente in der Sammlung dient.
7. Dokumentenstruktur und Wachstum
Dies geschieht als Ergebnis des Push-Vorgangs, bei dem Filialdokumente in ein Array-Feld verschoben werden oder wenn einem vorhandenen Dokument neue Felder hinzugefügt werden. Das Dokumentenwachstum hat einige Rückschläge, z. B. für eine begrenzte Sammlung, wenn die Größe geändert wird, schlägt die Operation automatisch fehl. Bei einer MMAPv1-Speicher-Engine verschieben Versionen vor 3.0 das Dokument auf die Festplatte, wenn die Dokumentgröße überschritten wird. In neueren Versionen ab 3.0 gibt es jedoch ein Konzept von Power of 2 Sized Allocations, das die Wahrscheinlichkeit solcher Neuzuweisungen reduziert und die effektive Wiederverwendung des freigegebenen Datensatzbereichs ermöglicht. Wenn Sie erwarten, dass Ihre Daten wachsen, sollten Sie Ihr Datenmodell umgestalten, um Verweise zwischen Daten in unterschiedlichen Dokumenten zu verwenden, anstatt ein denormalisiertes Datenmodell zu verwenden. Um ein Dokumentenwachstum zu vermeiden, können Sie auch eine Vorabzuweisungsstrategie verwenden /P>
8. Datenlebenszyklus
Ziehen Sie für eine Anwendung, die nur die kürzlich eingefügten Dokumente verwendet, die Verwendung einer begrenzten Sammlung in Betracht, deren Funktionen oben besprochen wurden.
Sie können auch die Time-to-Live-Funktion für Ihre Sammlung einstellen. Dies gilt durchaus für Zugriffstoken in der Funktion zum Zurücksetzen des Passworts für eine Anwendung.
Lebensdauer (TTL)
Dies ist eine Erfassungseinstellung, die es Mongod ermöglicht, Daten nach einer bestimmten Dauer automatisch zu entfernen. Standardmäßig wird dieses Konzept für maschinengenerierte Ereignisdaten, Protokolle und Sitzungsinformationen angewendet, die für einen begrenzten Zeitraum bestehen bleiben müssen.
Beispiel:
db.log_events.createIndex( { "createdAt": 1 }, { expireAfterSeconds: 3600 } )
Wir haben einen Index „createdAt“ erstellt und einen „expirateAfterSeconds“-Wert von 3600 angegeben, was 1 Stunde nach dem Erstellungszeitpunkt liegt. Wenn wir nun ein Dokument einfügen wie:
db.log_events.insert( {
"createdAt": new Date(),
"logEvent": 2,
"logMessage": "This message was recorded."
} )
Dieses Dokument wird 1 Stunde nach dem Einfügen gelöscht.
Sie können auch eine bestimmte Uhrzeit festlegen, zu der das Dokument gelöscht werden soll. Erstellen Sie dazu zunächst einen Index, z. B.:
db.log_events.createIndex( { "expireAt": 1 }, { expireAfterSeconds: 0 } )
Jetzt können wir ein Dokument einfügen und den Zeitpunkt angeben, wann es gelöscht werden soll.
db.log_events.insert( {
"expireAt": new Date(December 12, 2018 18:00:00'),
"logEvent": 2,
"logMessage": "Success!"
} )
Dieses Dokument wird automatisch gelöscht, wenn der Wert von expireAt älter ist als die Anzahl der Sekunden, die in expireAfterSeconds angegeben ist, also in diesem Fall 0.
Schlussfolgerung
Die Datenmodellierung ist ein umfangreiches Unterfangen für jedes Anwendungsdesign, um die Datenbankleistung zu verbessern. Berücksichtigen Sie vor dem Einfügen von Daten in Ihre Datenbank die Anforderungen der Anwendung und die besten Datenmodellmuster, die Sie implementieren sollten. Außerdem können wichtige Facetten von Anwendungen erst durch die Implementierung eines geeigneten Datenmodells realisiert werden.