Angenommen, wir haben eine App für das soziale Netzwerk (mit NodeJS, Express) und MongoDB als primäre Datenbank-Engine.
Bei den meisten API-Aufrufen von Clients (mobile App, Web-App usw.) möchte ich keine komplexe Abfrage für jede Anfrage erstellen. Diese Art von Anfragen kann von der Cache-Schicht, zum Beispiel Redis, beantwortet werden.
Aber meine Frage ist, wie / wann sollte ich die Cache-Ebene aktualisieren, da alle Schreiboperationen in der MongoDB-Datenbank ausgeführt werden, nicht die Cache-Ebene (Redis). Was ist der richtige Ansatz / Architektur, um dieses Problem anzugehen?
Angenommen, wir haben eine App für das soziale Netzwerk (mit NodeJS, Express) und MongoDB als primäre Datenbank-Engine.
Bei den meisten API-Aufrufen von Clients (mobile App, Web-App usw.) möchte ich keine komplexe Abfrage für jede Anfrage erstellen. Diese Art von Anfragen kann von der Cache-Schicht, zum Beispiel Redis, beantwortet werden.
Aber meine Frage ist, wie / wann sollte ich die Cache-Ebene aktualisieren, da alle Schreiboperationen in der MongoDB-Datenbank ausgeführt werden, nicht die Cache-Ebene (Redis). Was ist der richtige Ansatz / Architektur, um dieses Problem anzugehen?
Dies ist bereits in der Referenzarchitektur für MongoDB Open-Source-Projekt namens "Socialite" implementiert , obwohl es in Java und nicht Knoten ist .js, also basieren meine Antworten auf meinem Erfahrungsstress und dem Testen dieses Codes.
Wie Sie an der Implementierung des Status-Feeds sehen können, verfügt im Feed über die Option fanoutOnWrite cache , die einen Cache erstellen ( Dokument mit begrenzter Größe) für aktive Benutzer, wobei die Anzahl der letzten Einträge im Cache-Dokument begrenzt wird (diese Zahl ist konfigurierbar).
Die Schlüsselprinzipien dieser Implementierung bestehen darin, dass sich die Inhaltsanforderungen von den Anforderungen des Zeitleisten-Caches unterscheiden und zuerst die Datenbank für den Inhalt schreiben und dann den Cache aktualisieren (falls vorhanden) ). Dieser Teil kann asynchron durchgeführt werden , falls gewünscht. Das Update verwendet "capped arrays" aka aktualisiert die Slice-Funktionalität , um automatisch einen neuen Wert zu setzen / Inhalt auf das Array und hacken die älteste gleichzeitig aus.
Erstellen Sie keinen Cache für einen Benutzer, wenn dieser noch nicht existiert (wenn er sich nie anmeldet, verschwenden Sie den Aufwand). Optional können Sie Caches basierend auf einigen TTL-Parametern ablaufen lassen.
Wenn Sie bei der Anmeldung einen Cache für einen Benutzer lesen und dieser nicht vorhanden ist, greifen Sie auf "fanoutOnRead" zurück (wodurch der gesamte Inhalt der Benutzer abgefragt wird), und erstellen Sie dann ihren Cache aus diesem Ergebnis.
Im Socialite-Projekt wurde MongoDB für alle Backends verwendet, aber beim Benchmarking mussten wir feststellen, dass der Timeline-Cache nicht repliziert oder beibehalten werden musste. Daher wurden seine MongoDB-Server nur im Speicher konfiguriert (kein Journal, keine Replikation) , keine Festplattenspülung), die Ihrer Redis-Anwendung entspricht. Wenn du den Cache verlierst, wird er einfach aus dem permanenten Content-DB "on demand" wiederhergestellt.
Idel Ansatz ist zurückschreiben Cache-Weg. Sie können zuerst mongodb schreiben und dann nach redis schreiben. Es ist am häufigsten.
Eine andere Möglichkeit ist, Sie können zuerst Redisis schreiben und Async-Nachrichten senden, indem Sie redis verwenden (wie Q) Ein Thread kann die Nachricht konsumieren und lesen, sie in mongoDB schreiben.
Die erste Option ist einfacher zu implementieren. Die zweite Option kann eine große Anzahl von Schreibvorgängen unterstützen. Wie ich weiß, ist das mongodb-Lock-Problem noch nicht gelöst (es wurde von globaler Sperre auf db-Level-Sperre behoben) Die zweite Option kann erheblich sein, um eine solche Sperrkonkurrenz zu reduzieren.
Da es sich bei Ihrer Frage um Architektur handelt, beginnt sie mit "Angenommen ..."
Gründe für die Auswahl von mongoDB?
Mit Postgres bekomme ich eine bessere Leistung als mongoDB und das Beste von relationalen und schemalosen Dokumenten mit Postgres json / jsonb-Unterstützung, die tatsächlich schneller ist als mongoDB. Mit Postgres erhalten Sie eine ZUVERLÄSSIGE kampferprobte Datenbank, die ausgezeichnete Leistung, Skalierbarkeit und vor allem erlaubt, nachts zu schlafen und Ihren Urlaub zu genießen.
Sie können postgres LISTEN / NOTIFY auch für Echtzeitereignisse verwenden, damit Sie Redis-Cachebusting durchführen können.
Hier ist ein Beispiel für die Verwendung von postgres LISTEN / NOTIFY in nodejs: Ссылка
Hier finden Sie einige umfassende Leistungsbenchmarks für Postgres 9.4 als schemales / noSQL-Dokumentspeicher gegenüber mongoDB:
Um Redis zu einer brauchbaren Option für eine Cache-Schicht gegenüber MongoDB zu machen, müsste man einige Daten pumpen, wenn man bedenkt, dass MongoDB selbst über einen Arbeitssatz verfügt, der im RAM gehalten wird; Als solche können beide tatsächlich aus dem Gedächtnis dienen, wenn Sie wissen, was Sie tun und planen Sie Ihr Schema richtig.
Normalerweise ist es das Ziel von massiven Sites wie craigslist (http://www.slideshare.net/jzawodn/living-with-sql-and-nosql-at-craigslist-a), sich an Redis für Caching zu wenden - Pragmatischer Ansatz "> Ссылка ), der, wie Sie auf Folie 7 dieser Präsentation sehen können, ihn für:
verwendetund mehr, aber Sie können leicht sehen, wie ihre memcached-Installation auch damit verbunden werden könnte, um bestimmte Postings einzuschließen, wenn MongoDB ihr primärer Speicher statt MySQL wäre.
Diese Präsentation an sich gibt Ihnen eine gute Vorstellung davon, wie andere Redis mit MongoDB verwenden.
Grundsätzlich wird es normalerweise verwendet, um Snapshots von Daten aufzunehmen, die normalerweise etwas zu langsam sind, um von der Datenbank zu kommen.
Hier sind einige verwandte Informationen, die ich verwenden werde, um meine Antwort ein wenig zu stoßen: Was ist Redis und wofür verwende ich es? . Ich empfehle Ihnen dringend, diese Frage zu lesen, da Sie dadurch mehr darüber erfahren, für welchen Anwendungsfall Redis eigentlich geeignet ist und was für eine Zwischenspeicherung möglich ist.
Benötigen Sie Transaktionen und Echtzeit-Schreibvorgänge? Wenn jemand ein Update auf Mongo schreibt, ist es absolut notwendig, dass die Kunden sofort über die Änderung informiert werden (1 Sekunde / Minute / Tag)?
Sind Ihre Daten wirklich wichtig, damit kein Schreibvorgang verloren geht? Wenn ja, können Sie nicht zuerst auf redis schreiben, außer mit AOF (was bei redis nicht der Standardmodus ist und viel langsamer ist). Transaktionen zwischen Mongo und Redis werden beispielsweise nicht so einfach zu implementieren sein.
Wenn Sie zuerst in redis schreiben, können Sie publish / subscribe verwenden, um einen abonnierten redis Client zu benachrichtigen, um den Wert in mongo zu aktualisieren, aber es gibt keine Garantie, dass Ihre Daten sicher übertragen werden, seien Sie gewarnt! Dies sollte jedoch der schnellste / performanteste Weg sein, alle Ihre Clients zu aktualisieren, die alle mit redis verbunden sind.
Sie können auch eine Abfrage mit Ihrem akzeptablen Intervall für Echtzeit zwischen redis und mongo definieren, um den Cache mit Änderungen von mongo auf redis (Entkopplung) zu aktualisieren, ohne direkt von Ihrem Code aus redis zu schreiben. Sie können dazu Listener ("Trigger" in Mongo) verwenden oder einen Dirty-Check verwenden.
Schließlich sind einige von mongo + redis zu couchbase wie viber gewandert, vielleicht solltest du es als eine Option betrachten? Ссылка
Es hängt wirklich von Ihren Bedürfnissen ab, aber hier ist eine ziemlich häufige:
%Vor%Die Daten sind manchmal etwas altbacken, aber für die meisten Anwendungsfälle ist das in Ordnung. Es funktioniert gut in Kombination mit einer Cache-Invalidierung, wenn wichtige Daten geschrieben werden:
%Vor%Aber das alles setzt niedriges Schreiben, hohes Lesen und einen stabilen Satz von Abfragen voraus.
Wie sieht Ihr Hochlast-Anwendungsfall aus?
Dies ist bereits in der Referenzarchitektur für MongoDB Open-Source-Projekt namens "Socialite" implementiert , obwohl es in Java und nicht Knoten ist .js, also basieren meine Antworten auf meinem Erfahrungsstress und dem Testen dieses Codes.
Wie Sie an der Implementierung des Status-Feeds sehen können, verfügt im Feed über die Option fanoutOnWrite cache , die einen Cache erstellen ( Dokument mit begrenzter Größe) für aktive Benutzer, wobei die Anzahl der letzten Einträge im Cache-Dokument begrenzt wird (diese Zahl ist konfigurierbar).
Die Schlüsselprinzipien dieser Implementierung bestehen darin, dass sich die Inhaltsanforderungen von den Anforderungen des Zeitleisten-Caches unterscheiden und zuerst die Datenbank für den Inhalt schreiben und dann den Cache aktualisieren (falls vorhanden) ). Dieser Teil kann asynchron durchgeführt werden , falls gewünscht. Das Update verwendet "capped arrays" aka aktualisiert die Slice-Funktionalität , um automatisch einen neuen Wert zu setzen / Inhalt auf das Array und hacken die älteste gleichzeitig aus.
Erstellen Sie keinen Cache für einen Benutzer, wenn dieser noch nicht existiert (wenn er sich nie anmeldet, verschwenden Sie den Aufwand). Optional können Sie Caches basierend auf einigen TTL-Parametern ablaufen lassen.
Wenn Sie bei der Anmeldung einen Cache für einen Benutzer lesen und dieser nicht vorhanden ist, greifen Sie auf "fanoutOnRead" zurück (wodurch der gesamte Inhalt der Benutzer abgefragt wird), und erstellen Sie dann ihren Cache aus diesem Ergebnis.
Im Socialite-Projekt wurde MongoDB für alle Backends verwendet, aber beim Benchmarking mussten wir feststellen, dass der Timeline-Cache nicht repliziert oder beibehalten werden musste. Daher wurden seine MongoDB-Server nur im Speicher konfiguriert (kein Journal, keine Replikation) , keine Festplattenspülung), die Ihrer Redis-Anwendung entspricht. Wenn du den Cache verlierst, wird er einfach aus dem permanenten Content-DB "on demand" wiederhergestellt.
Idel Ansatz ist zurückschreiben Cache-Weg. Sie können zuerst mongodb schreiben und dann nach redis schreiben. Es ist am häufigsten.
Eine andere Möglichkeit ist, Sie können zuerst Redisis schreiben und Async-Nachrichten senden, indem Sie redis verwenden (wie Q) Ein Thread kann die Nachricht konsumieren und lesen, sie in mongoDB schreiben.
Die erste Option ist einfacher zu implementieren. Die zweite Option kann eine große Anzahl von Schreibvorgängen unterstützen. Wie ich weiß, ist das mongodb-Lock-Problem noch nicht gelöst (es wurde von globaler Sperre auf db-Level-Sperre behoben) Die zweite Option kann erheblich sein, um eine solche Sperrkonkurrenz zu reduzieren.
Da es sich bei Ihrer Frage um Architektur handelt, beginnt sie mit "Angenommen ..."
Gründe für die Auswahl von mongoDB?
Mit Postgres bekomme ich eine bessere Leistung als mongoDB und das Beste von relationalen und schemalosen Dokumenten mit Postgres json / jsonb-Unterstützung, die tatsächlich schneller ist als mongoDB. Mit Postgres erhalten Sie eine ZUVERLÄSSIGE kampferprobte Datenbank, die ausgezeichnete Leistung, Skalierbarkeit und vor allem erlaubt, nachts zu schlafen und Ihren Urlaub zu genießen.
Sie können postgres LISTEN / NOTIFY auch für Echtzeitereignisse verwenden, damit Sie Redis-Cachebusting durchführen können.
Hier ist ein Beispiel für die Verwendung von postgres LISTEN / NOTIFY in nodejs: Ссылка
Hier finden Sie einige umfassende Leistungsbenchmarks für Postgres 9.4 als schemales / noSQL-Dokumentspeicher gegenüber mongoDB:
Um Redis zu einer brauchbaren Option für eine Cache-Schicht gegenüber MongoDB zu machen, müsste man einige Daten pumpen, wenn man bedenkt, dass MongoDB selbst über einen Arbeitssatz verfügt, der im RAM gehalten wird; Als solche können beide tatsächlich aus dem Gedächtnis dienen, wenn Sie wissen, was Sie tun und planen Sie Ihr Schema richtig.
Normalerweise ist es das Ziel von massiven Sites wie craigslist (http://www.slideshare.net/jzawodn/living-with-sql-and-nosql-at-craigslist-a), sich an Redis für Caching zu wenden - Pragmatischer Ansatz "> Ссылка ), der, wie Sie auf Folie 7 dieser Präsentation sehen können, ihn für:
verwendetund mehr, aber Sie können leicht sehen, wie ihre memcached-Installation auch damit verbunden werden könnte, um bestimmte Postings einzuschließen, wenn MongoDB ihr primärer Speicher statt MySQL wäre.
Diese Präsentation an sich gibt Ihnen eine gute Vorstellung davon, wie andere Redis mit MongoDB verwenden.
Grundsätzlich wird es normalerweise verwendet, um Snapshots von Daten aufzunehmen, die normalerweise etwas zu langsam sind, um von der Datenbank zu kommen.
Hier sind einige verwandte Informationen, die ich verwenden werde, um meine Antwort ein wenig zu stoßen: Was ist Redis und wofür verwende ich es? . Ich empfehle Ihnen dringend, diese Frage zu lesen, da Sie dadurch mehr darüber erfahren, für welchen Anwendungsfall Redis eigentlich geeignet ist und was für eine Zwischenspeicherung möglich ist.
Benötigen Sie Transaktionen und Echtzeit-Schreibvorgänge? Wenn jemand ein Update auf Mongo schreibt, ist es absolut notwendig, dass die Kunden sofort über die Änderung informiert werden (1 Sekunde / Minute / Tag)?
Sind Ihre Daten wirklich wichtig, damit kein Schreibvorgang verloren geht? Wenn ja, können Sie nicht zuerst auf redis schreiben, außer mit AOF (was bei redis nicht der Standardmodus ist und viel langsamer ist). Transaktionen zwischen Mongo und Redis werden beispielsweise nicht so einfach zu implementieren sein.
Wenn Sie zuerst in redis schreiben, können Sie publish / subscribe verwenden, um einen abonnierten redis Client zu benachrichtigen, um den Wert in mongo zu aktualisieren, aber es gibt keine Garantie, dass Ihre Daten sicher übertragen werden, seien Sie gewarnt! Dies sollte jedoch der schnellste / performanteste Weg sein, alle Ihre Clients zu aktualisieren, die alle mit redis verbunden sind.
Sie können auch eine Abfrage mit Ihrem akzeptablen Intervall für Echtzeit zwischen redis und mongo definieren, um den Cache mit Änderungen von mongo auf redis (Entkopplung) zu aktualisieren, ohne direkt von Ihrem Code aus redis zu schreiben. Sie können dazu Listener ("Trigger" in Mongo) verwenden oder einen Dirty-Check verwenden.
Schließlich sind einige von mongo + redis zu couchbase wie viber gewandert, vielleicht solltest du es als eine Option betrachten? Ссылка