Echtzeitabfragen im großen Maßstab verstehen

In diesem Dokument finden Sie eine Anleitung zur Skalierung Ihrer serverlosen Anwendung über Tausende von Vorgängen pro Sekunde oder Hunderttausende gleichzeitiger Nutzer. Dieses Dokument enthält erweiterte Themen, die Ihnen helfen, das System besser zu verstehen. Wenn Sie gerade erst mit Firestore beginnen, lesen Sie stattdessen den Schnellstartleitfaden.

Firestore und die Firebase Mobile/Web SDKs bieten ein leistungsstarkes Modell für die Entwicklung serverloser Anwendungen, bei denen clientseitiger Code direkt auf die Datenbank. Mit den SDKs können Clients in Echtzeit Aktualisierungen der Daten überwachen. Mit Echtzeitaktualisierungen können Sie responsive Apps erstellen, für die keine Serverinfrastruktur erforderlich ist. Es ist zwar sehr einfach, etwas in Betrieb zu nehmen, aber es ist hilfreich, die Einschränkungen der Systeme zu kennen, aus denen Firestore besteht, damit Ihre serverlose App bei steigendem Traffic skaliert und eine gute Leistung erzielt.

In den folgenden Abschnitten finden Sie Hinweise zur Skalierung Ihrer App.

Datenbankspeicherort in der Nähe der Nutzer auswählen

Das folgende Diagramm zeigt die Architektur einer Echtzeit-App:

Beispiel für eine Echtzeit-App-Architektur

Wenn eine App, die auf dem Gerät eines Nutzers ausgeführt wird (Mobilgerät oder Web), eine Verbindung zu Firestore weitergeleitet wird, Firestore-Frontend-Server im selben Region, in der sich Ihre Datenbank befindet. Beispiel: Wenn sich Ihre Datenbank in us-east1 befindet, geht die Verbindung auch zu einem Firestore-Front-End auch in us-east1. Diese Verbindungen sind und bleiben geöffnet, bis sie von der App explizit geschlossen werden. Die Frontend liest Daten aus den zugrunde liegenden Firestore-Speichersystemen.

Die Entfernung zwischen dem physischen Standort eines Nutzers und dem Speicherort der Firestore-Datenbank wirkt sich auf die Latenz aus, die der Nutzer erfährt. Beispiel: Nutzer in Indien, dessen App mit einer Datenbank in einer Google Cloud-Region in Nordamerika kommuniziert die Nutzung langsamer und die App weniger knackig, als wenn die Datenbank sich näher befinden, etwa in Indien oder in einem anderen Teil Asiens.

Einhaltung von Zuverlässigkeitsvorgaben

Die folgenden Themen verbessern die Zuverlässigkeit Ihrer App oder wirken sich darauf aus:

Offlinemodus aktivieren

Die Firebase SDKs ermöglichen Offline-Datenpersistenz. Wenn der Parameter App auf dem Gerät des Nutzers keine Verbindung zu Firestore herstellen kann, Die Anwendung ist weiterhin nutzbar, weil mit lokal zwischengespeicherten Daten gearbeitet wird. Dadurch wird sichergestellt, auch bei instabilen Internetverbindungen oder mehrere Stunden oder Tage lang vollständig den Zugriff verlieren. Weitere Informationen zum Offlinemodus finden Sie unter Offlinedaten aktivieren.

Informationen zu automatischen Wiederholungsversuchen

Die Firebase SDKs kümmern sich um Wiederholungsversuche und die Wiederherstellung unterbrochener Verbindungen. So können Sie vorübergehende Fehler vermeiden, durch einen Neustart von Servern oder Netzwerkproblemen zwischen Client und Datenbank.

Zwischen regionalen und multiregionalen Standorten wählen

Bei der Wahl zwischen regionalen und multiregionale Standorte. Der Hauptunterschied besteht darin, wie Daten repliziert werden. Dadurch werden die Verfügbarkeitsgarantien Ihrer App erhöht. Eine multiregionale Instanz bietet eine höhere Zuverlässigkeit beim Bereitstellen und erhöht die Langlebigkeit Ihrer Daten. Der Nachteil sind jedoch die Kosten.

Das Echtzeit-Abfragesystem verstehen

Mit Echtzeitabfragen, auch Snapshot-Listener genannt, kann die App Änderungen in der Datenbank überwachen und Benachrichtigungen mit niedriger Latenz erhalten, sobald sich die Daten ändern. Eine App kann dasselbe Ergebnis erzielen, indem sie die Datenbank regelmäßig auf Updates prüft. Das ist jedoch oft langsamer, teurer und erfordert mehr Code. Beispiele zum Einrichten und Verwenden von Echtzeitabfragen finden Sie unter Echtzeitaktualisierungen abrufen. In den folgenden Abschnitten erfahren Sie mehr über die Funktionsweise von Snapshot-Listenern und einige Best Practices für die Skalierung von Echtzeitabfragen bei gleichzeitiger Beibehaltung der Leistung.

Stellen Sie sich zwei Nutzer vor, die über eine App, die mit einem der mobilen SDKs erstellt wurde.

Client A schreibt in die Datenbank, um Dokumente in einer Sammlung hinzuzufügen und zu aktualisieren. mit dem Namen chatroom:

collection chatroom:
    document message1:
      from: 'Sparky'
      message: 'Welcome to Firestore!'

    document message2:
      from: 'Santa'
      message: 'Presents are coming'

Client B wartet mit einem Snapshot-Listener auf Aktualisierungen in derselben Sammlung. Kunde B wird sofort benachrichtigt, wenn jemand eine neue Nachricht erstellt. Das folgende Diagramm zeigt die Architektur hinter einem Snapshot-Listener:

Architektur einer Snapshot-Listener-Verbindung

Die folgende Ereignissequenz findet statt, wenn Client B einen Snapshot verbindet Listener für die Datenbank:

  1. Client B öffnet eine Verbindung zu Firestore und registriert einen Listener, indem er über das Firebase SDK einen Aufruf an onSnapshot(collection("chatroom")) sendet. Dieser Listener kann stundenlang aktiv bleiben.
  2. Das Firestore-Frontend fragt das zugrunde liegende Speichersystem ab, um den Datensatz zu initialisieren. Es werden alle übereinstimmenden Ergebnisse geladen. Dokumente. Dies wird als Abfrage bezeichnet. Das System prüft dann die Firebase-Sicherheitsregeln der Datenbank, um zu bestätigen, dass der Nutzer auf diese Daten zugreifen kann. Wenn der Nutzer autorisiert ist, gibt die Datenbank die Daten an den Nutzer zurück.
  3. Die Abfrage von Client B wird dann in den Listener-Modus verschoben. Der Listener registriert die mit einem Abo-Handler und wartet auf Aktualisierungen der Daten.
  4. Client A sendet jetzt einen Schreibvorgang, um ein Dokument zu ändern.
  5. Die Datenbank überträgt die Dokumentänderung per Commit an die Ihres Speichersystems.
  6. Transaktionsweise überträgt das System dasselbe Update an eine interne changelog. Das Änderungsprotokoll legt eine strenge Reihenfolge der Änderungen fest.
  7. Beim Änderungsprotokoll werden die aktualisierten Daten dann auf einen Pool von Abonnements ausgeweitet. Handler.
  8. Ein Reverse-Query-Matcher wird ausgeführt, um zu prüfen, ob das aktualisierte Dokument mit derzeit registrierten Snapshot-Listenern übereinstimmt. In diesem Beispiel entspricht das Dokument dem Snapshot-Listener von Client B. Wie der Name schon sagt, können Sie sich den umgekehrten Abfrage-Matcher als normale Datenbankabfrage, aber in umgekehrter Reihenfolge. Anstatt nach Dokumenten zu suchen, die mit einer Suchanfrage übereinstimmen, werden effizient Suchanfragen nach solchen gesucht, die mit einem eingehenden Dokument übereinstimmen. Wenn eine Übereinstimmung gefunden wird, leitet das System das betreffende Dokument an die Snapshot-Listener weiter. Anschließend prüft das System die Firebase-Sicherheitsregeln der Datenbank, um sicherzustellen, dass nur autorisierte Nutzer die Daten erhalten.
  9. Das System leitet die Dokumentaktualisierung an das SDK auf dem Gerät von Client B weiter und der onSnapshot-Callback wird ausgelöst. Wenn die lokale Persistenz aktiviert ist, wendet das SDK das Update auch auf den lokalen Cache an.

Ein wichtiger Teil der Skalierbarkeit von Firestore hängt vom Fan-Out dem Änderungsprotokoll zu den Abo-Handlern und den Frontend-Servern. Durch die Verzweigung kann eine einzelne Datenänderung effizient weitergegeben werden, um Millionen von Echtzeitabfragen und verbundenen Nutzern zu dienen. Durch die Ausführung vieler Repliken all dieser Komponenten in mehreren Zonen (oder mehreren Regionen im Fall einer multiregionalen Bereitstellung) erreicht Firestore eine hohe Verfügbarkeit und Skalierbarkeit.

Hinweis: Alle Lesevorgänge, die über mobile und Web-SDKs ausgeführt werden, folgen dem oben beschriebenen Modell. Sie führen eine Abfrageabfrage gefolgt vom Überwachungsmodus durch. um Konsistenzgarantien zu gewährleisten. Das gilt auch für Echtzeit-Zuhörer, Aufrufe zum Abrufen eines Dokuments und One-Shot-Abfragen. Sie können sich die Abrufvorgänge einzelner Dokumente und einmalige Abfragen als kurzlebige Snapshot-Listener vorstellen, die ähnliche Leistungseinschränkungen haben.

Best Practices für die Skalierung von Echtzeitabfragen anwenden

Wenden Sie die folgenden Best Practices an, um skalierbare Echtzeitabfragen zu entwerfen.

Hohen Schreib-Traffic im System verstehen

In diesem Abschnitt erfahren Sie, wie das System auf eine steigende Anzahl von Schreibanfragen reagiert.

Firestore-Änderungslogs, die den Echtzeitabfragen zugrunde liegen automatisch horizontal skaliert werden, wenn der Schreib-Traffic steigt. Wenn die Schreibrate für eine Datenbank über die Kapazität eines einzelnen Servers hinausgeht, wird der Änderungsverlauf auf mehrere Server aufgeteilt und die Abfrageverarbeitung beginnt, Daten von mehreren Abo-Handlern anstelle von einem zu verwenden. Aus Sicht des Clients und des SDKs ist das alles transparent und es sind keine Maßnahmen von der App erforderlich, wenn es zu Aufteilungen kommt. Das folgende Diagramm zeigt, Echtzeitabfragen skalieren:

Architektur des Fan-Outs für Änderungslogs

Mit der automatischen Skalierung können Sie Ihren Schreibtraffic unbegrenzt erhöhen. Wenn der Traffic jedoch ansteigt, kann es einige Zeit dauern, bis das System reagiert. Folgen Sie den Empfehlungen der 5-5-5-Regel, um das Erstellen eines Schreibhotspots zu vermeiden. Key Visualizer ist ein ein nützliches Tool zur Analyse von Schreib-Hotspots.

Viele Anwendungen weisen ein vorhersehbares organisches Wachstum auf, das Firestore durch ohne Vorsichtsmaßnahmen einzugehen. Bei Batch-Arbeitslasten wie dem Importieren eines großen Datensatzes können Schreibvorgänge jedoch zu schnell ansteigen. Berücksichtigen Sie beim Entwerfen Ihrer App, woher die Schreibzugriffe stammen.

Verstehen, wie Schreib- und Lesevorgänge interagieren

Sie können sich das Echtzeit-Abfragesystem als eine Pipeline vorstellen, die eine Verbindung mit Lesern kommunizieren. Jedes Mal, wenn ein Dokument erstellt, aktualisiert oder gelöscht wird, wird die Änderung vom Speichersystem an die derzeit registrierten Listener weitergegeben. Die Struktur des Änderungsprotokolls von Firestore garantiert starke Konsistenz, was bedeutet, dass Ihre App nie Benachrichtigungen Aktualisierungen, die im Vergleich zum Zeitpunkt, zu dem die Daten per Commit übergeben wurden, nicht in der richtigen Reihenfolge sind Änderungen. Dies vereinfacht die App-Entwicklung, indem Grenzfälle in Bezug auf Datenkonsistenz.

Diese verbundene Pipeline bedeutet, dass ein Schreibvorgang oder Sperrenkonflikte, kann sich negativ auf Lesevorgänge auswirken. Wenn Schreibvorgänge fehlschlagen oder eine Drosselung auftritt, kann ein Lesevorgang auf konsistente Daten aus dem Änderungsprotokoll wartet. Wenn dies in Ihrer App der Fall ist, kann es sowohl zu langsamen Schreibvorgängen als auch zu entsprechenden langen Reaktionszeiten bei Abfragen kommen. Hotspots sind der Schlüssel, um dieses Problem zu vermeiden.

Dokumente und Schreibvorgänge klein halten

Wenn Sie Anwendungen mit Snapshot-Listenern erstellen, sollen Nutzer sich schnell über Datenänderungen informieren. Versuchen Sie, die Größe möglichst klein zu halten. Das System kann kleine Dokumente mit Dutzenden von Feldern sehr schnell durch das System leiten. Größere Dokumente mit Hunderten von Feldern und großen Datenmengen benötigen länger zu verarbeiten.

Bevorzugen Sie außerdem kurze, schnelle Commit- und Schreibvorgänge, um die Latenz niedrig zu halten. Große Batches können aus Sicht des Autors zu einem höheren Durchsatz führen aber die Benachrichtigungszeit für Snapshot-Listener verlängern. Dies ist im Vergleich zur Verwendung anderer Datenbanksysteme, können Sie die Leistung mit Batching verbessern.

Effiziente Zuhörer verwenden

Wenn die Schreibraten für Ihre Datenbank steigen, verteilt Firestore die Datenverarbeitung auf viele Server. Der Fragmentierungsalgorithmus von Firestore versucht, Daten aus der Sammlung oder Sammlungsgruppe auf demselben Änderungsprotokollserver. Die versucht das System, den möglichen Schreibdurchsatz zu maximieren, während die Anzahl so wenig Server wie möglich an der Verarbeitung einer Anfrage beteiligt sind.

Bestimmte Muster können jedoch zu einem suboptimalen Verhalten für Snapshots führen. zu hören. Wenn Ihre App die meisten Daten z. B. auf einem muss der Listener möglicherweise eine Verbindung zu vielen Servern herstellen, um alle Daten, die es benötigt. Das gilt auch dann, wenn Sie einen Abfragefilter anwenden. Verbinden... erhöht das Risiko langsamerer Antworten.

Um diese langsameren Antworten zu vermeiden, entwerfen Sie Ihr Schema und Ihre Anwendung so, dass das System können Hörer bedient werden, ohne viele verschiedene Server nutzen zu müssen. Es könnte funktionieren Ihre Daten am besten in kleinere Sammlungen mit geringeren Schreibraten aufzuteilen.

Das ist vergleichbar mit Leistungsabfragen, in einer relationalen Datenbank, die vollständige Tabellenscans erfordern. In einer relationalen entspricht eine Abfrage, die einen vollständigen Tabellenscan erfordert, Snapshot-Listener, der sich eine Sammlung mit hoher Abwanderung ansieht. Die Leistung ist möglicherweise langsam. im Vergleich zu einer Abfrage, die die Datenbank mit einem spezifischeren Index verarbeiten kann. Eine Abfrage mit einem spezifischeren Index ist wie ein Snapshot-Listener, der ein einzelnes Dokument oder eine Sammlung beobachtet, die sich seltener ändert. Sie sollten einen Lasttest für Ihre App ausführen, um das Verhalten und die Anforderungen Ihres Anwendungsfalls besser zu verstehen.

Schnelle Abfragen

Ein weiterer wichtiger Aspekt bei responsiven Echtzeitabfragen besteht darin, dafür zu sorgen, dass die Abfrage zum Bootstrapping der Daten schnell und effizient ist. Wenn ein neuer Snapshot-Listener zum ersten Mal eine Verbindung herstellt, muss der Listener den Parameter und an das Gerät des Nutzers senden. Langsame Abfragen verlangsamen Ihre App. Dazu gehören z. B. Suchanfragen, viele Dokumente oder Abfragen zu lesen, die nicht die entsprechenden Indexe verwenden.

Unter bestimmten Umständen kann ein Listener auch von einem aktiven Status in einen Polling-Status wechseln. Das geschieht automatisch und ist für die SDKs und Ihre App transparent. Die folgenden Bedingungen können einen Polling-Status auslösen:

Wenn Ihre Abfrageabfragen schnell genug sind, wird ein Abfragestatus transparent. für die Nutzer Ihrer App.

Langlebige Listener bevorzugen

Es ist oft am wichtigsten, die Zuhörer so lange wie möglich zu öffnen und am Leben zu halten. eine kostengünstige Möglichkeit, Anwendungen zu erstellen, die Firestore nutzen. Bei Verwendung Firestore werden Ihnen die an Ihre Anwendung zurückgegebenen Dokumente in Rechnung gestellt. und nicht zur Aufrechterhaltung einer offenen Verbindung. Ein langlebiger Snapshot-Listener liest während seiner Lebensdauer nur die Daten, die für die Abfrage erforderlich sind. Dieses enthält einen anfänglichen Abfragevorgang, gefolgt von Benachrichtigungen, wenn die Daten tatsächlich ändert. Mit One-Shot-Abfragen werden Daten, die möglicherweise seit der letzten Ausführung der Abfrage durch die Anwendung nicht geändert wurden.

In Fällen, in denen Ihre Anwendung eine hohe Datenrate verbrauchen muss, erstellen Snapshot-Listener nicht angemessen sein. Wenn Ihr Anwendungsfall z. B. viele Dokumente über einen längeren Zeitraum über eine Verbindung pro Sekunde, sollten Sie sich für einmalige Abfragen entscheiden, die mit geringerer Häufigkeit ausgeführt werden.

Weitere Informationen