Najlepsze praktyki dotyczące Cloud Firestore

Skorzystaj z najlepszych praktyk wymienionych tutaj jako krótkiego odniesienia podczas tworzenia aplikacji korzystającej z Cloud Firestore.

Lokalizacja bazy danych

Tworząc instancję bazy danych, wybierz lokalizację bazy danych najbliższą użytkownikom i zasobom obliczeniowym. Dalekosiężne przeskoki sieciowe są bardziej podatne na błędy i zwiększają opóźnienia zapytań.

Aby zmaksymalizować dostępność i trwałość aplikacji, wybierz lokalizację obejmującą wiele regionów i umieść krytyczne zasoby obliczeniowe w co najmniej dwóch regionach.

Wybierz lokalizację regionalną , aby uzyskać niższe koszty, mniejsze opóźnienia w zapisie, jeśli aplikacja jest wrażliwa na opóźnienia, lub kolokację z innymi zasobami GCP .

Identyfikatory dokumentów

  • Unikaj identyfikatorów dokumentów . I .. .
  • Unikaj używania ukośników / w identyfikatorach dokumentów.
  • Nie używaj monotonicznie rosnących identyfikatorów dokumentów, takich jak:

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

    Takie sekwencyjne identyfikatory mogą prowadzić do punktów aktywnych wpływających na opóźnienia.

Nazwy pól

  • Unikaj następujących znaków w nazwach pól, ponieważ wymagają one dodatkowej zmiany znaczenia:

    • . okres
    • [ lewy nawias
    • ] prawy nawias
    • * gwiazdka
    • ` cofanie się

Indeksy

Zmniejsz opóźnienie zapisu

Głównym czynnikiem powodującym opóźnienie zapisu jest rozwarstwienie indeksu. Najlepsze praktyki ograniczania rozproszenia indeksu to:

  • Ustaw wykluczenia indeksu na poziomie kolekcji . Łatwym rozwiązaniem domyślnym jest wyłączenie indeksowania malejąco i tablicowego. Usunięcie nieużywanych wartości indeksowanych również obniży koszty przechowywania .

  • Zmniejsz liczbę dokumentów w transakcji. W przypadku pisania dużej liczby dokumentów należy rozważyć użycie modułu zapisującego masowego zamiast modułu zapisującego wsadowego.

Wyłączenia indeksowe

W przypadku większości aplikacji możesz polegać na automatycznym indeksowaniu, a także na linkach do komunikatów o błędach, aby zarządzać indeksami. Można jednak dodać wyjątki jednopolowe w następujących przypadkach:

Sprawa Opis
Duże pola tekstowe

Jeśli masz pole znakowe, które często przechowuje długie wartości ciągów, których nie używasz do wykonywania zapytań, możesz obniżyć koszty przechowywania, zwalniając pole z indeksowania.

Wysokie współczynniki zapisu do kolekcji zawierającej dokumenty z kolejnymi wartościami

Jeśli indeksujesz pole, które zwiększa się lub zmniejsza sekwencyjnie między dokumentami w kolekcji, na przykład znacznik czasu, maksymalna szybkość zapisu do kolekcji wynosi 500 zapisów na sekundę. Jeśli nie wykonujesz zapytań w oparciu o pole z kolejnymi wartościami, możesz wyłączyć pole z indeksowania, aby ominąć ten limit.

Na przykład w przypadku użycia IoT z dużą szybkością zapisu kolekcja zawierająca dokumenty z polem sygnatury czasowej może zbliżać się do limitu 500 zapisów na sekundę.

Pola TTL

Jeśli korzystasz z zasad TTL (time-to-live) , pamiętaj, że pole TTL musi być znacznikiem czasu. Indeksowanie pól TTL jest domyślnie włączone i może wpływać na wydajność przy większym natężeniu ruchu. Najlepszym rozwiązaniem jest dodanie wyjątków pojedynczych pól dla pól TTL.

Duża tablica lub pola mapy

Duże pola tablicowe lub mapy mogą zbliżać się do limitu 40 000 wpisów indeksu na dokument. Jeśli nie odpytujesz w oparciu o dużą tablicę lub pole mapy, powinieneś wyłączyć je z indeksowania.

Operacje odczytu i zapisu

  • Dokładna maksymalna szybkość, z jaką aplikacja może aktualizować pojedynczy dokument, zależy w dużym stopniu od obciążenia. Aby uzyskać więcej informacji, zobacz Aktualizacje pojedynczego dokumentu .

  • Używaj wywołań asynchronicznych, jeśli są dostępne, zamiast wywołań synchronicznych. Wywołania asynchroniczne minimalizują wpływ opóźnień. Rozważmy na przykład aplikację, która potrzebuje wyniku wyszukiwania dokumentu i wyników zapytania przed wyświetleniem odpowiedzi. Jeśli wyszukiwanie i zapytanie nie są powiązane z danymi, nie ma potrzeby synchronicznego oczekiwania na zakończenie wyszukiwania przed zainicjowaniem zapytania.

  • Nie używaj przesunięć. Zamiast tego użyj kursorów . Użycie przesunięcia pozwala jedynie uniknąć zwrotu pominiętych dokumentów do aplikacji, ale dokumenty te są nadal pobierane wewnętrznie. Pominięte dokumenty wpływają na opóźnienie zapytania, a aplikacja jest obciążana opłatami za operacje odczytu wymagane do ich pobrania.

Ponowne próby transakcji

Zestawy SDK Cloud Firestore i biblioteki klienckie automatycznie ponawiają nieudane transakcje, aby poradzić sobie z przejściowymi błędami. Jeśli Twoja aplikacja uzyskuje dostęp do Cloud Firestore bezpośrednio za pośrednictwem interfejsów API REST lub RPC zamiast za pośrednictwem pakietu SDK, powinna implementować ponowne próby transakcji, aby zwiększyć niezawodność.

Aktualizacje w czasie rzeczywistym

Najlepsze praktyki związane z aktualizacjami w czasie rzeczywistym można znaleźć w artykule Omówienie zapytań w czasie rzeczywistym na dużą skalę .

Projektowanie na skalę

Poniższe najlepsze rozwiązania opisują, jak unikać sytuacji powodujących problemy z rywalizacją.

Aktualizacje pojedynczego dokumentu

Projektując aplikację, zastanów się, jak szybko aplikacja aktualizuje pojedyncze dokumenty. Najlepszym sposobem scharakteryzowania wydajności obciążenia jest wykonanie testów obciążenia. Dokładna maksymalna szybkość, z jaką aplikacja może aktualizować pojedynczy dokument, zależy w dużym stopniu od obciążenia. Czynniki obejmują szybkość zapisu, rywalizację między żądaniami i liczbę indeksów, których to dotyczy.

Operacja zapisu dokumentu aktualizuje dokument i wszystkie powiązane z nim indeksy, a Cloud Firestore synchronicznie stosuje operację zapisu w kworum replik. Przy wystarczająco dużej szybkości zapisu baza danych zacznie napotykać rywalizację, większe opóźnienia lub inne błędy.

Wysokie współczynniki odczytu, zapisu i usuwania w wąskim zakresie dokumentów

Unikaj dużej szybkości odczytu lub zapisu, aby leksykograficznie zamykać dokumenty, w przeciwnym razie w aplikacji wystąpią błędy rywalizacji. Ten problem nazywany jest hotspotem i w aplikacji może wystąpić hotspot, jeśli wykona jedną z poniższych czynności:

  • Tworzy nowe dokumenty z bardzo dużą szybkością i przydziela własne, monotonicznie rosnące identyfikatory.

    Cloud Firestore przydziela identyfikatory dokumentów za pomocą algorytmu rozproszenia. Jeśli tworzysz nowe dokumenty przy użyciu automatycznych identyfikatorów dokumentów, nie powinieneś spotkać się z hotspotem podczas zapisów.

  • Tworzy nowe dokumenty z dużą szybkością w kolekcji zawierającej kilka dokumentów.

  • Tworzy nowe dokumenty z monotonicznie rosnącym polem, takim jak znacznik czasu, w bardzo szybkim tempie.

  • Usuwa dokumenty w kolekcji z dużą szybkością.

  • Zapisuje do bazy danych z bardzo dużą szybkością, bez stopniowego zwiększania ruchu.

Unikaj pomijania usuniętych danych

Unikaj zapytań, które pomijają ostatnio usunięte dane. Zapytanie może wymagać pominięcia dużej liczby wpisów indeksu, jeśli wcześniejsze wyniki zapytania zostały niedawno usunięte.

Przykładem obciążenia, które może wymagać pominięcia wielu usuniętych danych, jest takie, które próbuje znaleźć najstarsze elementy pracy w kolejce. Zapytanie może wyglądać następująco:

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()

Za każdym razem, gdy to zapytanie jest uruchamiane, skanuje wpisy indeksu dla created pola we wszystkich ostatnio usuniętych dokumentach. Spowalnia to zapytania.

Aby poprawić wydajność, użyj metody start_at , aby znaleźć najlepsze miejsce do rozpoczęcia. Na przykład:

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()

UWAGA: W powyższym przykładzie zastosowano monotonicznie rosnące pole, które jest antywzorem dla dużych szybkości zapisu.

Zwiększanie ruchu

Powinieneś stopniowo zwiększać ruch do nowych kolekcji lub zamykać dokumenty leksykograficznie, aby dać Cloud Firestore wystarczająco dużo czasu na przygotowanie dokumentów na wzmożony ruch. Zalecamy zacząć od maksymalnie 500 operacji na sekundę do nowej kolekcji, a następnie zwiększać ruch o 50% co 5 minut. Możesz w podobny sposób zwiększyć ruch zapisu, ale pamiętaj o standardowych limitach Cloud Firestore . Upewnij się, że operacje są rozłożone stosunkowo równomiernie w całym zakresie kluczy. Nazywa się to zasadą „500/50/5”.

Migracja ruchu do nowej kolekcji

Stopniowe zwiększanie wydajności jest szczególnie ważne w przypadku migracji ruchu z aplikacji z jednej kolekcji do drugiej. Prostym sposobem poradzenia sobie z tą migracją jest przeczytanie ze starej kolekcji, a jeśli dokument nie istnieje, odczytanie z nowej kolekcji. Mogłoby to jednak spowodować nagły wzrost ruchu na leksykograficznie zamykających dokumentach w nowym zbiorze. Cloud Firestore może nie być w stanie efektywnie przygotować nowej kolekcji na wzmożony ruch, zwłaszcza gdy zawiera ona niewiele dokumentów.

Podobny problem może wystąpić w przypadku zmiany identyfikatorów wielu dokumentów w tej samej kolekcji.

Najlepsza strategia migracji ruchu do nowej kolekcji zależy od modelu danych. Poniżej znajduje się przykładowa strategia znana jako odczyty równoległe . Będziesz musiał określić, czy ta strategia jest skuteczna dla Twoich danych, a ważnym czynnikiem będzie wpływ kosztów równoległych operacji podczas migracji.

Czytanie równoległe

Aby zaimplementować odczyty równoległe podczas migracji ruchu do nowej kolekcji, najpierw przeczytaj ze starej kolekcji. Jeśli brakuje dokumentu, przeczytaj z nowego zbioru. Wysoki współczynnik odczytów nieistniejących dokumentów może prowadzić do hotspotów, dlatego pamiętaj o stopniowym zwiększaniu obciążenia nowej kolekcji. Lepszą strategią jest skopiowanie starego dokumentu do nowej kolekcji, a następnie usunięcie starego dokumentu. Stopniowo zwiększaj odczyty równoległe, aby mieć pewność, że Cloud Firestore będzie w stanie obsłużyć ruch do nowej kolekcji.

Możliwą strategią stopniowego zwiększania liczby odczytów lub zapisów w nowej kolekcji jest użycie deterministycznego skrótu identyfikatora użytkownika w celu wybrania losowego odsetka użytkowników próbujących napisać nowe dokumenty. Upewnij się, że wynik skrótu identyfikatora użytkownika nie jest zniekształcony ani przez funkcję, ani przez zachowanie użytkownika.

W międzyczasie uruchom zadanie wsadowe, które skopiuje wszystkie dane ze starych dokumentów do nowej kolekcji. Twoje zadanie wsadowe powinno unikać zapisów w kolejnych identyfikatorach dokumentów, aby zapobiec powstawaniu punktów aktywnych. Po zakończeniu zadania wsadowego będzie można czytać tylko z nowej kolekcji.

Udoskonaleniem tej strategii jest jednorazowa migracja małych grup użytkowników. Dodaj pole do dokumentu użytkownika, które śledzi status migracji tego użytkownika. Wybierz grupę użytkowników do migracji na podstawie skrótu identyfikatora użytkownika. Użyj zadania wsadowego, aby przeprowadzić migrację dokumentów dla tej grupy użytkowników i użyj odczytu równoległego dla użytkowników w trakcie migracji.

Należy pamiętać, że nie można łatwo przywrócić zmian, chyba że podczas fazy migracji wykonasz podwójne zapisy zarówno starych, jak i nowych jednostek. Zwiększyłoby to poniesione koszty Cloud Firestore.

Prywatność

  • Unikaj przechowywania poufnych informacji w identyfikatorze projektu w chmurze. Identyfikator projektu Cloud może zostać zachowany po zakończeniu projektu.
  • Ze względu na najlepszą praktykę dotyczącą zgodności danych zalecamy, aby nie przechowywać poufnych informacji w nazwach dokumentów i nazwach pól dokumentów.

Zapobiegaj nieautoryzowanemu dostępowi

Zapobiegaj nieautoryzowanym operacjom na bazie danych dzięki regułom bezpieczeństwa Cloud Firestore. Na przykład użycie reguł pozwala uniknąć scenariusza, w którym złośliwy użytkownik wielokrotnie pobiera całą bazę danych.

Dowiedz się więcej o korzystaniu z reguł bezpieczeństwa Cloud Firestore .