Datenbanksysteme haben den Auftrag, Datenkonsistenz und -integrität zu gewährleisten, insbesondere wenn es sich um kritische Daten handelt. Diese Aspekte werden durch ACID-Transaktionen in MongoDB erzwungen. Eine ACID-Transaktion sollte einige definierte Regeln für die Datengültigkeit erfüllen, bevor Aktualisierungen an der Datenbank vorgenommen werden, andernfalls sollte sie abgebrochen werden und keine Änderungen an der Datenbank vorgenommen werden. Alle Datenbanktransaktionen werden als eine einzige logische Operation betrachtet und während der Ausführungszeit wird die Datenbank in einen inkonsistenten Zustand versetzt, bis die Änderungen festgeschrieben wurden. Operationen, die den Status der Datenbank erfolgreich ändern, werden als Schreibtransaktionen bezeichnet, während Operationen, die die Datenbank nicht aktualisieren, sondern nur Daten abrufen, als Nur-Lese-Transaktionen bezeichnet werden. ACID ist ein Akronym für Atomicity, Consistency, Isolation und Durability.
Eine Datenbank ist eine gemeinsam genutzte Ressource, auf die von verschiedenen Benutzern zu unterschiedlichen oder gleichzeitigen Zeiten zugegriffen werden kann. Aus diesem Grund können gleichzeitige Transaktionen auftreten, und wenn sie nicht gut verwaltet werden, können sie zu Systemabstürzen, Hardwarefehlern, Deadlocks, langsamer Datenbankleistung oder Wiederholungen bei der Ausführung derselben Transaktion führen.
Was sind ACID-Regeln?
Alle Datenbanksysteme müssen die ACID-Eigenschaften erfüllen, um die Datenintegrität zu gewährleisten.
Atomizität
Eine Transaktion wird als einzelne Operationseinheit betrachtet, die entweder vollständig erfolgreich sein oder vollständig fehlschlagen kann. Eine Transaktion kann nicht teilweise ausgeführt werden. Wenn irgendeine Bedingung beim Abfragen einer Transaktion fehlschlägt, schlägt die gesamte Transaktion vollständig fehl und die Datenbank bleibt unverändert. Wenn Sie beispielsweise Geld von Konto X auf Y überweisen möchten, gibt es hier zwei Transaktionen, die erste dient dazu, Geld von X zu entfernen, und die zweite, um die Gelder in Y zu erfassen. Wenn die erste Transaktion fehlschlägt, das Ganze Transaktion wird abgebrochen
Konsistenz
Wenn eine Operation ausgeführt wird, befindet sich die Datenbank vor der Ausführung in einem konsistenten Zustand und sollte dies auch nach jeder Transaktion bleiben. Selbst wenn es eine Aktualisierung gibt, sollte die Transaktion die Datenbank immer in einen gültigen Zustand bringen und die Datenbankinvarianten beibehalten. Sie können beispielsweise keinen Primärschlüssel löschen, der in einer anderen Sammlung als Fremdschlüssel referenziert wurde. Alle Daten müssen die definierten Einschränkungen erfüllen, um eine Datenbeschädigung durch eine illegale Transaktion zu verhindern.
Isolierung
Mehrere Transaktionen, die gleichzeitig ausgeführt werden, werden ausgeführt, ohne sich gegenseitig zu beeinflussen, und ihr Ergebnis sollte dasselbe sein, wenn sie nacheinander ausgeführt würden. Wenn zwei oder mehr Transaktionen dieselben Dokumente in MongoDB ändern, kann es zu einem Konflikt kommen. Die Datenbank erkennt einen Konflikt unmittelbar bevor er festgeschrieben wird. Die erste Operation zum Erlangen einer Sperre für das Dokument wird fortgesetzt, während die andere fehlschlägt und eine Konfliktfehlermeldung angezeigt wird.
Haltbarkeit
Dies schreibt vor, dass, sobald die Transaktion festgeschrieben wurde, die Änderungen jederzeit aufrechterhalten werden sollten, selbst im Falle eines Systemausfalls, beispielsweise aufgrund von Stromausfällen oder einer Unterbrechung der Internetverbindung.
MongoDB-ACID-Transaktionen
MongoDB ist eine dokumentbasierte NoSQL-Datenbank mit einem flexiblen Schema. Transaktionen sind keine Vorgänge, die für jeden Schreibvorgang ausgeführt werden sollten, da sie gegenüber dem Schreiben eines einzelnen Dokuments höhere Leistungskosten verursachen. Mit einer dokumentbasierten Struktur und einem denormalisierten Datenmodell wird der Bedarf an Transaktionen minimiert. Da MongoDB das Einbetten von Dokumenten ermöglicht, müssen Sie nicht unbedingt eine Transaktion verwenden, um einen Schreibvorgang auszuführen.
MongoDB Version 4.0 bietet Multi-Document-Transaktionsunterstützung nur für Replica-Set-Bereitstellungen und wahrscheinlich wird die Version 4.2 die Unterstützung für fragmentierte Bereitstellungen erweitern (gemäß den Versionshinweisen).
Beispiel einer Transaktion:
Stellen Sie zuerst sicher, dass Sie ein Replikat-Set eingerichtet haben. Angenommen, Sie haben eine Datenbank namens App und eine Sammlung, in der Benutzer in der Mongo-Shell die folgenden Befehle ausführen:
$mongos und Sie sollten so etwas wie username:PRIMARY>
sehen$use app
$db.users.insert([{_id:1, name: ‘Brian’}, {_id:2, name: ‘Sheila’}, {_id:3, name: ‘James’}])
Wir müssen eine Sitzung für unsere Transaktion starten:
$db.getMongo().startSession() and you should see something like
session { "id" : UUID("dcfa8de5-627d-3b1c-a890-63c9a355520c") }
Mit dieser Sitzung können wir weitere Benutzer hinzufügen, indem wir eine Transaktion mit den folgenden Befehlen verwenden
$session.startTransaction()
session.getDatabase(‘app’).users.insert({_id:4, name: ‘Hitler’})
Sie erhalten WriteResult({“nInsterted”:2})
Die Transaktion wurde noch nicht festgeschrieben und die normale $db.users.find({}) gibt uns nur die zuvor gespeicherten Benutzer. Aber wenn wir die
$session.getDatabase(“app”).users.find()
der zuletzt hinzugefügte Datensatz ist in den zurückgegebenen Ergebnissen verfügbar. Um diese Transaktion festzuschreiben, führen wir den folgenden Befehl aus
$session.commitTransaction()
Die Transaktionsänderung wird im Speicher gespeichert, weshalb die Daten auch nach einem Ausfall bei der Wiederherstellung verfügbar sind.
ACID-Transaktionen mit mehreren Dokumenten in MongoDB
Dies sind Operationen mit mehreren Anweisungen, die nacheinander ausgeführt werden müssen, ohne sich gegenseitig zu beeinflussen. Für das obige Beispiel können wir zwei Transaktionen erstellen, eine zum Hinzufügen eines Benutzers und eine andere zum Aktualisieren eines Benutzers mit einem Altersfeld. D.h.
$session.startTransaction()
db.users.insert({_id:6, name “Ibrahim”})
db.users.updateOne({_id:3 , {$set:{age:50}}})
session.commit_transaction()
Transaktionen können auf Operationen gegen mehrere Dokumente angewendet werden, die in einer oder mehreren Sammlungen/Datenbanken enthalten sind. Änderungen aufgrund von Dokumententransaktionen wirken sich nicht auf die Leistung für nicht verwandte Arbeitslasten aus oder erfordern sie nicht. Bis die Transaktion festgeschrieben ist, werden nicht festgeschriebene Schreibvorgänge weder auf die sekundären Knoten repliziert noch sind sie außerhalb der Transaktionen lesbar.
Best Practices für MongoDB-Transaktionen
Die Multi-Dokument-Transaktionen werden nur in der WiredTiger-Speicher-Engine unterstützt. Wie bereits erwähnt, erfordern nur sehr wenige Anwendungen Transaktionen, und wenn ja, sollten wir versuchen, sie kurz zu halten. Andernfalls kann es für eine einzelne ACID-Transaktion zu einer übermäßigen Belastung des WiredTiger-Cache führen, wenn Sie versuchen, eine übermäßige Anzahl von Vorgängen auszuführen. Der Cache wird immer angewiesen, den Zustand für alle nachfolgenden Schreibvorgänge beizubehalten, seit der älteste Snapshot erstellt wurde. Das bedeutet, dass sich während der gesamten Dauer der Transaktion neue Schreibvorgänge im Cache ansammeln und erst geleert werden, nachdem Transaktionen, die derzeit auf alten Snapshots ausgeführt werden, festgeschrieben oder abgebrochen werden. Für die beste Datenbankleistung bei der Transaktion sollten Entwickler Folgendes berücksichtigen:
- Ändern Sie immer eine kleine Anzahl von Dokumenten in einer Transaktion. Andernfalls müssen Sie die Transaktion in verschiedene Teile aufteilen und die Dokumente in verschiedenen Stapeln verarbeiten. Verarbeiten Sie höchstens 1000 Dokumente gleichzeitig.
- Vorübergehende Ausnahmen wie das Warten auf die Wahl des primären und vorübergehenden Netzwerkfehlers können zum Abbruch der Transaktion führen. Entwickler sollten eine Logik einrichten, um die Transaktion erneut zu versuchen, wenn die definierten Fehler angezeigt werden.
- Konfigurieren Sie die optimale Dauer für die Ausführung der Transaktion aus den standardmäßig von MongoDB bereitgestellten 60 Sekunden. Verwenden Sie außerdem die Indizierung, damit sie einen schnellen Datenzugriff innerhalb der Transaktion ermöglichen kann. Sie haben auch die Flexibilität, die Transaktion bei der Behandlung von Zeitüberschreitungen zu optimieren, indem Sie sie in Stapel aufteilen, die ihre Ausführung innerhalb der Zeitlimits ermöglichen.
- Zerlegen Sie Ihre Transaktion in eine kleine Gruppe von Vorgängen, damit sie den Größenbeschränkungen von 16 MB entspricht. Andernfalls, wenn die Operation zusammen mit der Oplog-Beschreibung dieses Limit überschreitet, wird die Transaktion abgebrochen.
- Alle Daten, die sich auf eine Entität beziehen, sollten in einer einzigen, reichhaltigen Dokumentenstruktur gespeichert werden. Dies dient dazu, die Anzahl der Dokumente zu reduzieren, die zwischengespeichert werden müssen, wenn verschiedene Felder geändert werden.
Einschränkungen von Transaktionen
- Sie können eine Sammlung nicht innerhalb einer Transaktion erstellen oder löschen.
- Transaktionen können keine Schreibvorgänge in eine begrenzte Sammlung ausführen
- Die Ausführung von Transaktionen nimmt viel Zeit in Anspruch und kann irgendwie die Leistung der Datenbank verlangsamen.
- Die Transaktionsgröße ist auf 16 MB begrenzt, sodass alle Transaktionen, die diese Größe überschreiten, in kleinere Transaktionen aufgeteilt werden müssen.
- Das Unterwerfen einer großen Anzahl von Dokumenten für eine Transaktion kann übermäßigen Druck auf die WiredTiger-Engine ausüben, und da sie auf die Snapshot-Fähigkeit angewiesen ist, werden große, nicht geleerte Operationen im Speicher zurückgehalten. Dies führt zu Leistungseinbußen in der Datenbank.
Fazit
In MongoDB Version 4.0 wurde die Unterstützung mehrerer Dokumententransaktionen für Replikatsätze als Funktion zur Verbesserung der Datenintegrität und -konsistenz eingeführt. Es gibt jedoch nur sehr wenige Anwendungen, die bei der Verwendung von MongoDB Transaktionen erfordern würden. Es gibt Einschränkungen gegen diese Funktion, die sie in Bezug auf das Transaktionskonzept etwas unausgereift machen. Beispielsweise werden Transaktionen für einen Sharding-Cluster nicht unterstützt und dürfen die Größenbeschränkung von 16 MB nicht überschreiten. Die Datenmodellierung bietet eine bessere Struktur zur Reduzierung von Transaktionen in Ihrer Datenbank. Sofern Sie es nicht mit Sonderfällen zu tun haben, ist es besser, Transaktionen in MongoDB zu vermeiden.