Ich weiß, dass es hier ähnliche Fragen gibt, aber sie fordern mich entweder auf, zu regulären RDBMS-Systemen zurückzukehren, wenn ich Transaktionen benötige oder atomare Operationen oder ein zweiphasiges Festschreiben verwende . Die zweite Lösung scheint die beste Wahl zu sein. Das dritte möchte ich nicht verfolgen, da anscheinend viele Dinge schief gehen könnten und ich es nicht in jeder Hinsicht testen kann. Es fällt mir schwer, mein Projekt für atomare Operationen umzugestalten. Ich weiß nicht, ob dies aus meiner eingeschränkten Sicht geschieht (ich habe bisher nur mit SQL-Datenbanken gearbeitet) oder ob dies tatsächlich nicht möglich ist.
Wir möchten MongoDB in unserem Unternehmen pilotieren. Wir haben ein relativ einfaches Projekt ausgewählt - ein SMS-Gateway. Es ermöglicht unserer Software, SMS-Nachrichten an das Mobilfunknetz zu senden, und das Gateway erledigt die Drecksarbeit: Die Kommunikation mit den Anbietern erfolgt über verschiedene Kommunikationsprotokolle. Das Gateway verwaltet auch die Abrechnung der Nachrichten. Jeder Kunde, der sich für den Service bewirbt, muss ein Guthaben kaufen. Das System verringert automatisch das Guthaben des Benutzers, wenn eine Nachricht gesendet wird, und verweigert den Zugriff, wenn das Guthaben nicht ausreicht. Auch weil wir Kunden von SMS-Anbietern von Drittanbietern sind, haben wir möglicherweise auch unsere eigenen Guthaben bei ihnen. Wir müssen auch diese im Auge behalten.
Ich begann darüber nachzudenken, wie ich die erforderlichen Daten mit MongoDB speichern kann, wenn ich die Komplexität reduziere (externe Abrechnung, SMS-Versand in der Warteschlange). Aus der SQL-Welt stammend, würde ich eine separate Tabelle für Benutzer erstellen, eine andere für SMS-Nachrichten und eine zum Speichern der Transaktionen in Bezug auf den Kontostand der Benutzer. Angenommen, ich erstelle separate Sammlungen für alle in MongoDB.
Stellen Sie sich eine SMS-Sendeaufgabe mit den folgenden Schritten in diesem vereinfachten System vor:
Überprüfen Sie, ob der Benutzer über ein ausreichendes Gleichgewicht verfügt. Zugriff verweigern, wenn nicht genügend Guthaben vorhanden ist
Senden und Speichern der Nachricht in der SMS-Sammlung mit den Details und Kosten (im Live-System hätte die Nachricht ein
status
Attribut und eine Aufgabe würde sie zur Zustellung abholen und den Preis der SMS entsprechend ihrem aktuellen Status festlegen).Verringern Sie das Guthaben der Benutzer um die Kosten der gesendeten Nachricht
Protokollieren Sie die Transaktion in der Transaktionssammlung
Was ist das Problem damit? MongoDB kann atomare Aktualisierungen nur für ein Dokument durchführen. Im vorherigen Ablauf kann es vorkommen, dass sich ein Fehler einschleicht und die Nachricht in der Datenbank gespeichert wird, der Kontostand des Benutzers jedoch nicht aktualisiert und / oder die Transaktion nicht protokolliert wird.
Ich hatte zwei Ideen:
Erstellen Sie eine einzelne Sammlung für die Benutzer und speichern Sie den Kontostand als Feld, benutzerbezogene Transaktionen und Nachrichten als Unterdokumente im Benutzerdokument. Da wir Dokumente atomar aktualisieren können, wird das Transaktionsproblem dadurch gelöst. Nachteile: Wenn der Benutzer viele SMS-Nachrichten sendet, kann das Dokument groß werden und das 4-MB-Dokumentlimit erreicht werden. Vielleicht kann ich in solchen Szenarien Verlaufsdokumente erstellen, aber ich denke nicht, dass dies eine gute Idee wäre. Ich weiß auch nicht, wie schnell das System wäre, wenn ich immer mehr Daten auf dasselbe große Dokument übertragen würde.
Erstellen Sie eine Sammlung für Benutzer und eine für Transaktionen. Es gibt zwei Arten von Transaktionen: Kreditkauf mit positiver Kontostandänderung und Nachrichten mit negativer Kontostandänderung. Die Transaktion kann ein Unterdokument haben. Beispielsweise können in gesendeten Nachrichten die Details der SMS in die Transaktion eingebettet werden. Nachteile: Ich speichere das aktuelle Benutzerguthaben nicht, daher muss ich es jedes Mal berechnen, wenn ein Benutzer versucht, eine Nachricht zu senden, um festzustellen, ob die Nachricht durchlaufen werden kann oder nicht. Ich befürchte, diese Berechnung kann langsam werden, wenn die Anzahl der gespeicherten Transaktionen zunimmt.
Ich bin ein bisschen verwirrt darüber, welche Methode ich wählen soll. Gibt es andere Lösungen? Ich konnte online keine Best Practices finden, um diese Art von Problemen zu umgehen. Ich denke, viele Programmierer, die versuchen, sich mit der NoSQL-Welt vertraut zu machen, stehen am Anfang vor ähnlichen Problemen.
quelle
Antworten:
Ab 4.0 verfügt MongoDB über ACID-Transaktionen mit mehreren Dokumenten. Es ist geplant, zuerst diejenigen in Replikatsatzbereitstellungen zu aktivieren, gefolgt von den Sharded-Clustern. Transaktionen in MongoDB fühlen sich wie Transaktionsentwickler an, die mit relationalen Datenbanken vertraut sind - sie bestehen aus mehreren Anweisungen mit ähnlicher Semantik und Syntax (wie
start_transaction
undcommit_transaction
). Wichtig ist, dass die Änderungen an MongoDB, die Transaktionen ermöglichen, keine Auswirkungen auf die Leistung von Workloads haben, für die sie nicht erforderlich sind.Weitere Details finden Sie hier .
Wenn Sie verteilte Transaktionen haben, bedeutet dies nicht, dass Sie Ihre Daten wie in tabellarischen relationalen Datenbanken modellieren sollten. Nutzen Sie die Leistungsfähigkeit des Dokumentmodells und befolgen Sie die bewährten Methoden der Datenmodellierung.
quelle
Leben ohne Transaktionen
Transaktionen unterstützen ACID- Eigenschaften, aber obwohl keine Transaktionen vorhanden sind
MongoDB
, haben wir atomare Operationen. Nun, atomare Operationen bedeuten, dass wenn Sie an einem einzelnen Dokument arbeiten, diese Arbeit abgeschlossen wird, bevor jemand anderes das Dokument sieht. Sie werden alle Änderungen sehen, die wir vorgenommen haben, oder keine von ihnen. Und mit atomaren Operationen können Sie oft das Gleiche erreichen, was wir mit Transaktionen in einer relationalen Datenbank erreicht hätten. Der Grund dafür ist, dass wir in einer relationalen Datenbank Änderungen über mehrere Tabellen hinweg vornehmen müssen. Normalerweise müssen Tabellen verbunden werden, und deshalb möchten wir das alles auf einmal tun. Und da es mehrere Tabellen gibt, müssen wir eine Transaktion beginnen und all diese Aktualisierungen durchführen und dann die Transaktion beenden. Aber mitMongoDB
Wir werden die Daten einbetten, da wir sie vorab in Dokumenten zusammenfügen und es sich um diese umfangreichen Dokumente handelt, die eine Hierarchie aufweisen. Wir können oft das Gleiche erreichen. Wenn wir beispielsweise im Blog-Beispiel sicherstellen möchten, dass wir einen Blog-Beitrag atomar aktualisiert haben, können wir dies tun, da wir den gesamten Blog-Beitrag auf einmal aktualisieren können. Wo es sich um eine Reihe relationaler Tabellen handelt, müssten wir wahrscheinlich eine Transaktion öffnen, damit wir die Sammlung von Posts und Kommentaren aktualisieren können.Welche Ansätze können wir verfolgen
MongoDB
, um einen Mangel an Transaktionen zu überwinden?Update
,findAndModify
,$addToSet
(Innerhalb einer Aktualisierung) &$push
(innerhalb einer Aktualisierung) Operationen arbeiten atomar in einem einzigen Dokument.quelle
Überprüfen Sie diese heraus, durch Tokutek. Sie entwickeln ein Plugin für Mongo, das nicht nur Transaktionen verspricht, sondern auch die Leistung steigert.
quelle
Bringen Sie es auf den Punkt: Wenn die Transaktionsintegrität ein Muss ist, verwenden Sie MongoDB nicht, sondern nur Komponenten im System, die Transaktionen unterstützen. Es ist äußerst schwierig, etwas auf Komponenten aufzubauen, um ACID-ähnliche Funktionen für nicht ACID-kompatible Komponenten bereitzustellen. Abhängig von den einzelnen Anwendungsfällen kann es sinnvoll sein, Aktionen in irgendeiner Weise in transaktionale und nicht-transaktionale Aktionen zu unterteilen ...
quelle
Das ist eigentlich kein Problem. Der von Ihnen erwähnte Fehler ist entweder ein logischer (Fehler) oder ein E / A-Fehler (Netzwerk, Festplattenfehler). Diese Art von Fehler kann dazu führen, dass sowohl transaktionslose als auch Transaktionsspeicher in einem nicht konsistenten Zustand bleiben. Wenn zum Beispiel bereits SMS gesendet wurden, aber beim Speichern der Nachricht ein Fehler aufgetreten ist, kann das Senden von SMS nicht rückgängig gemacht werden. Dies bedeutet, dass es nicht protokolliert wird, das Benutzerguthaben nicht verringert wird usw.
Das eigentliche Problem hierbei ist, dass der Benutzer die Rennbedingungen nutzen und mehr Nachrichten senden kann, als sein Kontostand zulässt. Dies gilt auch für RDBMS, es sei denn, Sie senden SMS innerhalb einer Transaktion mit Sperrfeldsperre (was ein großer Engpass wäre). Als mögliche Lösung für MongoDB würde
findAndModify
zuerst verwendet, um das Guthaben zu reduzieren und es zu überprüfen, wenn es negativ ist, das Senden zu verbieten und den Betrag zurückzuerstatten (atomares Inkrement). Wenn dies positiv ist, senden Sie weiter und falls dies fehlschlägt, erstatten Sie den Betrag. Die Erfassung des Kontostandverlaufs kann auch verwaltet werden, um das Kontofeld zu korrigieren / zu überprüfen.quelle
Das Projekt ist einfach, aber Sie müssen Transaktionen für die Zahlung unterstützen, was das Ganze schwierig macht. So ist beispielsweise ein komplexes Portalsystem mit Hunderten von Sammlungen (Forum, Chat, Anzeigen usw.) in gewisser Hinsicht einfacher, denn wenn Sie ein Forum oder einen Chat-Eintrag verlieren, kümmert sich niemand wirklich darum. Wenn Sie andererseits einen Zahlungsvorgang verlieren, ist dies ein ernstes Problem.
Wenn Sie also wirklich ein Pilotprojekt für MongoDB möchten, wählen Sie eines, das in dieser Hinsicht einfach ist .
quelle
Transaktionen fehlen in MongoDB aus triftigen Gründen. Dies ist eines der Dinge, die MongoDB schneller machen.
In Ihrem Fall, wenn Transaktion ein Muss ist, scheint Mongo nicht gut zu passen.
Möglicherweise RDMBS + MongoDB, dies erhöht jedoch die Komplexität und erschwert die Verwaltung und Unterstützung von Anwendungen.
quelle
Dies ist wahrscheinlich der beste Blog, den ich bezüglich der Implementierung einer transaktionsähnlichen Funktion für Mongodb gefunden habe.!
Synchronisierungsflag: Am besten nur zum Kopieren von Daten aus einem Masterdokument
Job Queue: sehr allgemeiner Zweck, löst 95% der Fälle. Die meisten Systeme müssen ohnehin mindestens eine Jobwarteschlange haben!
Zwei-Phasen-Commit: Diese Technik stellt sicher, dass jede Entität immer über alle Informationen verfügt, die erforderlich sind, um einen konsistenten Zustand zu erreichen
Protokollabstimmung: Die robusteste Technik, ideal für Finanzsysteme
Versionierung: Bietet Isolation und unterstützt komplexe Strukturen
Lesen Sie dies für weitere Informationen: https://dzone.com/articles/how-implement-robust-and
quelle
Dies ist spät, aber ich denke, dies wird in Zukunft helfen. Ich benutze Redis, um eine Warteschlange zu erstellen , um dieses Problem zu lösen.
Anforderung: Das folgende
Bild zeigt, dass 2 Aktionen gleichzeitig ausgeführt werden müssen, Phase 2 und Phase 3 von Aktion 1 jedoch vor dem Start von Phase 2 von Aktion 2 oder umgekehrt beendet werden müssen (Eine Phase kann eine Anforderungs-REST-API, eine Datenbankanforderung oder die Ausführung von Javascript-Code sein ... ).
Wie eine Warteschlange Ihnen hilft Warteschlange Stellen Sie
sicher, dass nicht jeder Blockcode zwischen
lock()
undrelease()
in vielen Funktionen gleichzeitig ausgeführt wird. Isolieren Sie sie.So erstellen Sie eine Warteschlange
Ich werde mich nur darauf konzentrieren, wie Sie beim Erstellen einer Warteschlange auf der Backend-Site einen Teil der Race-Bedingungen vermeiden . Wenn Sie die Grundidee der Warteschlange nicht kennen, kommen Sie hierher .
Der folgende Code zeigt nur das Konzept, das Sie korrekt implementieren müssen.
Aber du musst dich selbst
isRunning()
setStateToRelease()
setStateToRunning()
isolieren, sonst bist du wieder mit Rennbedingungen konfrontiert. Dazu wähle ich Redis für ACID- Zwecke und skalierbar.Redis Dokument spricht über die Transaktion:
P / s:
Ich verwende Redis, da mein Dienst es bereits verwendet. Sie können dazu auch die Isolation auf andere Weise unterstützen.
Das
action_domain
in meinem Code ist oben für, wenn Sie nur Aktion 1 Aufruf von Benutzer A benötigen Blockieren Sie Aktion 2 von Benutzer A, blockieren Sie keinen anderen Benutzer. Die Idee ist, einen eindeutigen Schlüssel für die Sperre jedes Benutzers zu setzen.quelle
Transaktionen sind ab sofort in MongoDB 4.0 verfügbar. Probe hier
quelle