Best Practices für Cloud Firestore

Verwenden Sie die hier aufgeführten Best Practices als Kurzreferenz beim Erstellen einer Anwendung, die Cloud Firestore verwendet.

Datenbankspeicherort

Wählen Sie beim Erstellen Ihrer Datenbankinstanz den Datenbankstandort aus, der Ihren Benutzern und Rechenressourcen am nächsten liegt. Weitreichende Netzwerk-Hops sind fehleranfälliger und erhöhen die Abfragelatenz.

Um die Verfügbarkeit und Haltbarkeit Ihrer Anwendung zu maximieren, wählen Sie einen Standort mit mehreren Regionen aus und platzieren Sie kritische Rechenressourcen in mindestens zwei Regionen.

Wählen Sie einen regionalen Standort für geringere Kosten, für eine geringere Schreiblatenz, wenn Ihre Anwendung latenzempfindlich ist, oder für die gemeinsame Platzierung mit anderen GCP-Ressourcen .

Dokument-IDs

  • Vermeiden Sie die Dokument-IDs . Und .. .
  • Vermeiden Sie die Verwendung von / -Schrägstrichen in Dokument-IDs.
  • Verwenden Sie keine monoton ansteigenden Dokument-IDs wie:

    • Customer1 , Customer2 , Customer3 , ...
    • Product 1 , Product 2 , Product 3 , ...

    Solche sequentiellen IDs können zu Hotspots führen, die sich auf die Latenz auswirken.

Feldnamen

  • Vermeiden Sie die folgenden Zeichen in Feldnamen, da diese zusätzliche Escapezeichen erfordern:

    • . Zeitraum
    • [ linke Klammer
    • ] rechte Klammer
    • * Sternchen
    • ` Backtick

Indizes

Reduzieren Sie die Schreiblatenz

Der Hauptfaktor für die Schreiblatenz ist der Index-Fanout. Die besten Vorgehensweisen zur Reduzierung des Index-Fanouts sind:

  • Indexausnahmen auf Sammlungsebene festlegen. Eine einfache Standardeinstellung besteht darin, die absteigende Indizierung und die Array-Indizierung zu deaktivieren. Durch das Entfernen ungenutzter indizierter Werte werden auch die Speicherkosten gesenkt.

  • Reduzieren Sie die Anzahl der Dokumente in einer Transaktion. Wenn Sie eine große Anzahl von Dokumenten schreiben möchten, sollten Sie die Verwendung eines Massenschreibers anstelle des atomaren Stapelschreibers in Betracht ziehen.

Indexausnahmen

Bei den meisten Apps können Sie sich bei der Verwaltung Ihrer Indizes auf die automatische Indizierung sowie etwaige Fehlermeldungslinks verlassen. In den folgenden Fällen möchten Sie jedoch möglicherweise Ausnahmen für einzelne Felder hinzufügen:

Fall Beschreibung
Große Stringfelder

Wenn Sie über ein Zeichenfolgenfeld verfügen, das häufig lange Zeichenfolgenwerte enthält, die Sie nicht für Abfragen verwenden, können Sie die Speicherkosten senken, indem Sie das Feld von der Indizierung ausnehmen.

Hohe Schreibraten für eine Sammlung, die Dokumente mit sequenziellen Werten enthält

Wenn Sie ein Feld indizieren, das zwischen Dokumenten in einer Sammlung sequentiell zunimmt oder abnimmt, z. B. einen Zeitstempel, beträgt die maximale Schreibrate für die Sammlung 500 Schreibvorgänge pro Sekunde. Wenn Sie keine Abfragen basierend auf dem Feld mit sequenziellen Werten durchführen, können Sie das Feld von der Indizierung ausnehmen, um diese Beschränkung zu umgehen.

In einem IoT-Anwendungsfall mit einer hohen Schreibrate könnte sich beispielsweise eine Sammlung, die Dokumente mit einem Zeitstempelfeld enthält, der Grenze von 500 Schreibvorgängen pro Sekunde nähern.

TTL-Felder

Wenn Sie TTL-Richtlinien (Time-to-Live) verwenden, beachten Sie, dass das TTL-Feld ein Zeitstempel sein muss. Die Indizierung von TTL-Feldern ist standardmäßig aktiviert und kann sich bei höheren Datenverkehrsraten auf die Leistung auswirken. Fügen Sie als Best Practice Einzelfeldausnahmen für Ihre TTL-Felder hinzu.

Große Array- oder Kartenfelder

Große Array- oder Kartenfelder können die Grenze von 40.000 Indexeinträgen pro Dokument erreichen. Wenn Sie die Abfrage nicht auf der Grundlage eines großen Arrays oder Kartenfelds durchführen, sollten Sie es von der Indizierung ausnehmen.

Lese- und Schreibvorgänge

  • Die genaue maximale Rate, mit der eine App ein einzelnes Dokument aktualisieren kann, hängt stark von der Arbeitslast ab. Weitere Informationen finden Sie unter Aktualisierungen eines einzelnen Dokuments .

  • Verwenden Sie asynchrone Aufrufe, sofern verfügbar, anstelle von synchronen Aufrufen. Asynchrone Aufrufe minimieren die Auswirkungen auf die Latenz. Stellen Sie sich beispielsweise eine Anwendung vor, die das Ergebnis einer Dokumentsuche und die Ergebnisse einer Abfrage benötigt, bevor sie eine Antwort rendert. Wenn die Suche und die Abfrage keine Datenabhängigkeit aufweisen, ist es nicht erforderlich, synchron zu warten, bis die Suche abgeschlossen ist, bevor die Abfrage gestartet wird.

  • Verwenden Sie keine Offsets. Verwenden Sie stattdessen Cursor . Durch die Verwendung eines Offsets wird lediglich vermieden, dass die übersprungenen Dokumente an Ihre Anwendung zurückgegeben werden. Diese Dokumente werden jedoch weiterhin intern abgerufen. Die übersprungenen Dokumente wirken sich auf die Latenz der Abfrage aus und Ihrer Anwendung werden die zum Abrufen erforderlichen Lesevorgänge in Rechnung gestellt.

Transaktionen werden erneut versucht

Die Cloud Firestore SDKs und Client-Bibliotheken wiederholen fehlgeschlagene Transaktionen automatisch erneut, um vorübergehende Fehler zu beheben. Wenn Ihre Anwendung über die REST- oder RPC- APIs direkt statt über ein SDK auf Cloud Firestore zugreift, sollte Ihre Anwendung Transaktionswiederholungen implementieren, um die Zuverlässigkeit zu erhöhen.

Echtzeit-Updates

Best Practices im Zusammenhang mit Echtzeitaktualisierungen finden Sie unter Grundlegendes zu Echtzeitabfragen im großen Maßstab .

Maßgeschneidertes Design

Die folgenden Best Practices beschreiben, wie Sie Situationen vermeiden können, die zu Konfliktproblemen führen.

Aktualisierungen eines einzelnen Dokuments

Berücksichtigen Sie beim Entwerfen Ihrer App, wie schnell Ihre App einzelne Dokumente aktualisiert. Der beste Weg, die Leistung Ihrer Workload zu charakterisieren, ist die Durchführung von Lasttests. Die genaue maximale Rate, mit der eine App ein einzelnes Dokument aktualisieren kann, hängt stark von der Arbeitslast ab. Zu den Faktoren gehören die Schreibrate, Konflikte zwischen Anforderungen und die Anzahl der betroffenen Indizes.

Ein Dokumentschreibvorgang aktualisiert das Dokument und alle zugehörigen Indizes, und Cloud Firestore wendet den Schreibvorgang synchron auf ein Quorum von Replikaten an. Bei ausreichend hohen Schreibraten kommt es in der Datenbank zu Konflikten, höherer Latenz oder anderen Fehlern.

Hohe Lese-, Schreib- und Löschraten für einen schmalen Dokumentenbereich

Vermeiden Sie hohe Lese- oder Schreibraten, um Dokumente lexikographisch zu schließen, da sonst in Ihrer Anwendung Konfliktfehler auftreten. Dieses Problem wird als Hotspotting bezeichnet. Bei Ihrer Anwendung kann es zu Hotspotting kommen, wenn eine der folgenden Aktionen ausgeführt wird:

  • Erstellt mit sehr hoher Geschwindigkeit neue Dokumente und vergibt eigene, monoton ansteigende IDs.

    Cloud Firestore weist Dokument-IDs mithilfe eines Streualgorithmus zu. Bei Schreibvorgängen sollte es nicht zu Hotspotting kommen, wenn Sie neue Dokumente mit automatischen Dokument-IDs erstellen.

  • Erstellt in einer Sammlung mit wenigen Dokumenten in hoher Geschwindigkeit neue Dokumente.

  • Erstellt mit sehr hoher Geschwindigkeit neue Dokumente mit einem monoton wachsenden Feld, wie einem Zeitstempel.

  • Löscht Dokumente in einer Sammlung mit hoher Geschwindigkeit.

  • Schreibt mit sehr hoher Geschwindigkeit in die Datenbank, ohne dass der Datenverkehr allmählich zunimmt.

Vermeiden Sie es, gelöschte Daten zu überspringen

Vermeiden Sie Abfragen, die kürzlich gelöschte Daten überspringen. Eine Abfrage muss möglicherweise eine große Anzahl von Indexeinträgen überspringen, wenn die frühen Abfrageergebnisse kürzlich gelöscht wurden.

Ein Beispiel für einen Workload, der möglicherweise viele gelöschte Daten überspringen muss, ist der Versuch, die ältesten Arbeitselemente in der Warteschlange zu finden. Die Abfrage könnte wie folgt aussehen:

docs = db.collection('WorkItems').order_by('created').limit(100)
delete_batch = db.batch()
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
delete_batch.commit()

Bei jeder Ausführung dieser Abfrage werden die Indexeinträge für das created Feld in allen kürzlich gelöschten Dokumenten durchsucht. Dies verlangsamt Abfragen.

Um die Leistung zu verbessern, verwenden Sie die Methode start_at , um den besten Startpunkt zu finden. Zum Beispiel:

completed_items = db.collection('CompletionStats').document('all stats').get()
docs = db.collection('WorkItems').start_at(
    {'created': completed_items.get('last_completed')}).order_by(
        'created').limit(100)
delete_batch = db.batch()
last_completed = None
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
  last_completed = doc.get('created')

if last_completed:
  delete_batch.update(completed_items.reference,
                      {'last_completed': last_completed})
  delete_batch.commit()

HINWEIS: Das obige Beispiel verwendet ein monoton steigendes Feld, das ein Antimuster für hohe Schreibraten darstellt.

Den Verkehr ankurbeln

Sie sollten den Datenverkehr zu neuen Sammlungen schrittweise steigern oder Dokumente lexikographisch schließen, um Cloud Firestore genügend Zeit zu geben, Dokumente für den erhöhten Datenverkehr vorzubereiten. Wir empfehlen, mit maximal 500 Vorgängen pro Sekunde zu einer neuen Sammlung zu beginnen und den Datenverkehr dann alle 5 Minuten um 50 % zu erhöhen. Sie können Ihren Schreibverkehr auf ähnliche Weise steigern, beachten Sie jedoch die Standardlimits von Cloud Firestore . Stellen Sie sicher, dass die Vorgänge relativ gleichmäßig über den gesamten Tastenbereich verteilt sind. Dies wird als „500/50/5“-Regel bezeichnet.

Datenverkehr wird in eine neue Sammlung migriert

Eine schrittweise Steigerung ist besonders wichtig, wenn Sie App-Verkehr von einer Sammlung in eine andere migrieren. Eine einfache Möglichkeit, diese Migration zu handhaben, besteht darin, aus der alten Sammlung zu lesen. Wenn das Dokument nicht vorhanden ist, dann aus der neuen Sammlung. Dies könnte jedoch zu einem plötzlichen Anstieg des Datenverkehrs zu lexikographisch geschlossenen Dokumenten in der neuen Sammlung führen. Cloud Firestore ist möglicherweise nicht in der Lage, die neue Sammlung effizient auf erhöhten Datenverkehr vorzubereiten, insbesondere wenn sie nur wenige Dokumente enthält.

Ein ähnliches Problem kann auftreten, wenn Sie die Dokument-IDs vieler Dokumente innerhalb derselben Sammlung ändern.

Die beste Strategie für die Migration des Datenverkehrs zu einer neuen Sammlung hängt von Ihrem Datenmodell ab. Nachfolgend finden Sie eine Beispielstrategie, die als parallele Lesevorgänge bekannt ist. Sie müssen feststellen, ob diese Strategie für Ihre Daten effektiv ist. Ein wichtiger Gesichtspunkt sind die Kostenauswirkungen paralleler Vorgänge während der Migration.

Paralleles Lesen

Um beim Migrieren des Datenverkehrs zu einer neuen Sammlung parallele Lesevorgänge zu implementieren, lesen Sie zuerst aus der alten Sammlung. Wenn das Dokument fehlt, lesen Sie es aus der neuen Sammlung. Eine hohe Leserate nicht vorhandener Dokumente kann zu Hotspotting führen. Stellen Sie daher sicher, dass die Auslastung der neuen Sammlung schrittweise erhöht wird. Eine bessere Strategie besteht darin, das alte Dokument in die neue Sammlung zu kopieren und dann das alte Dokument zu löschen. Steigern Sie die parallelen Lesevorgänge schrittweise, um sicherzustellen, dass Cloud Firestore den Datenverkehr zur neuen Sammlung verarbeiten kann.

Eine mögliche Strategie zur schrittweisen Steigerung der Lese- oder Schreibvorgänge in einer neuen Sammlung besteht darin, einen deterministischen Hash der Benutzer-ID zu verwenden, um einen zufälligen Prozentsatz der Benutzer auszuwählen, die versuchen, neue Dokumente zu schreiben. Stellen Sie sicher, dass das Ergebnis des Benutzer-ID-Hashs weder durch Ihre Funktion noch durch das Benutzerverhalten verzerrt wird.

Führen Sie in der Zwischenzeit einen Batch-Job aus, der alle Ihre Daten aus den alten Dokumenten in die neue Sammlung kopiert. Ihr Batch-Job sollte Schreibvorgänge in sequentielle Dokument-IDs vermeiden, um Hotspots zu verhindern. Wenn der Batch-Job abgeschlossen ist, können Sie nur noch aus der neuen Sammlung lesen.

Eine Verfeinerung dieser Strategie besteht darin, jeweils kleine Gruppen von Benutzern zu migrieren. Fügen Sie dem Benutzerdokument ein Feld hinzu, das den Migrationsstatus dieses Benutzers verfolgt. Wählen Sie einen Batch von Benutzern zur Migration basierend auf einem Hash der Benutzer-ID aus. Verwenden Sie einen Stapelauftrag, um Dokumente für diesen Benutzerstapel zu migrieren, und verwenden Sie parallele Lesevorgänge für Benutzer während der Migration.

Beachten Sie, dass Sie kein einfaches Rollback durchführen können, es sei denn, Sie führen während der Migrationsphase doppelte Schreibvorgänge für die alten und neuen Entitäten durch. Dies würde die anfallenden Cloud Firestore-Kosten erhöhen.

Privatsphäre

  • Vermeiden Sie es, vertrauliche Informationen in einer Cloud-Projekt-ID zu speichern. Eine Cloud-Projekt-ID bleibt möglicherweise über die Lebensdauer Ihres Projekts hinaus erhalten.
  • Als Best Practice für die Datenkonformität empfehlen wir, keine vertraulichen Informationen in Dokumentnamen und Dokumentfeldnamen zu speichern.

Verhindern Sie unbefugten Zugriff

Verhindern Sie unbefugte Vorgänge in Ihrer Datenbank mit Cloud Firestore-Sicherheitsregeln. Durch die Verwendung von Regeln könnte beispielsweise ein Szenario vermieden werden, in dem ein böswilliger Benutzer wiederholt Ihre gesamte Datenbank herunterlädt.

Erfahren Sie mehr über die Verwendung von Cloud Firestore-Sicherheitsregeln .