Sprawdzone metody dotyczące Cloud Firestore

Podczas tworzenia aplikacji korzystającej z Cloud Firestore możesz się posłużyć sprawdzonymi metodami wymienionymi w tym artykule.

Lokalizacja bazy danych

Podczas tworzenia instancji bazy danych wybierz lokalizację bazy danych najbliższą użytkownikom i zasobom obliczeniowym. Długie ścieżki sieciowe są bardziej podatne na błędy i zwiększają opóźnienie zapytań.

Aby zmaksymalizować dostępność i trwałość aplikacji, wybierz lokalizację w wielu regionach i umieść krytyczne zasoby obliczeniowe w co najmniej 2 regionach.

Wybierz lokalizację w jednym regionie, aby obniżyć koszty, zmniejszyć opóźnienie zapisu (jeśli aplikacja jest wrażliwa na opóźnienia) lub aby umieścić zasoby w tej samej lokalizacji co inne zasoby GCP.

Identyfikatory dokumentów

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

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

    Takie sekwencyjne identyfikatory mogą prowadzić do powstawania hotspotów, które wpływają na opóźnienie.

Nazwy pól

  • Unikaj tych znaków w nazwach pól, ponieważ wymagają one dodatkowego kodowania:

    • . kropka
    • [ nawias otwierający
    • ] prawy nawias kwadratowy
    • * gwiazdka
    • ` grawis

Indeksy

Zmniejszanie opóźnienia zapisu

Głównym czynnikiem wpływającym na opóźnienie zapisu jest rozgałęzianie indeksu. Sprawdzone metody zmniejszania rozgałęziania indeksu:

  • Ustaw wykluczenia indeksu na poziomie kolekcji. Łatwym domyślnym ustawieniem jest wyłączenie indeksowania malejącego i tablic. Usunięcie nieużywanych indeksowanych wartości obniży też koszty przechowywania.

  • Zmniejsz liczbę dokumentów w transakcji. Jeśli chcesz zapisać dużą liczbę dokumentów, rozważ użycie narzędzia do zbiorczego zapisu zamiast atomowego narzędzia do zapisu wsadowego.

Wykluczenia indeksu

W przypadku większości aplikacji możesz polegać na automatycznym indeksowaniu oraz na linkach w komunikatach o błędach, aby zarządzać indeksami. W tych przypadkach możesz jednak dodać wykluczenia dotyczące pojedynczych pól:

Etui Opis
Pola z długimi ciągami znaków

Jeśli masz pole z ciągiem znaków, które często zawiera długie wartości, których nie używasz do wysyłania zapytań, możesz obniżyć koszty przechowywania, wyłączając indeksowanie tego pola.

Wysokie współczynniki zapisu w kolekcji zawierającej dokumenty z wartościami sekwencyjnymi

Jeśli indeksujesz pole, które rośnie lub maleje sekwencyjnie między dokumentami w kolekcji, np. sygnaturę czasową, maksymalny współczynnik zapisu w kolekcji wynosi 500 zapisów na sekundę. Jeśli nie wysyłasz zapytań na podstawie pola z wartościami sekwencyjnymi, możesz wyłączyć indeksowanie tego pola aby ominąć ten limit.

W przypadku zastosowania IoT z wysokim współczynnikiem zapisu, np. kolekcji zawierającej dokumenty z polem sygnatury czasowej, może zostać osiągnięty limit 500 zapisów na sekundę.

Pola TTL

Jeśli używasz zasad TTL (czas życia danych), pamiętaj, że pole TTL musi być sygnaturą czasową. Indeksowanie pól TTL jest domyślnie włączone i może wpływać na wydajność przy wyższych współczynnikach ruchu. Zalecamy dodanie wykluczeń automatycznego indeksowania dla pól TTL.

Pola z dużymi tablicami lub mapami

Pola z dużymi tablicami lub mapami mogą zbliżać się do limitu 40 tys. wpisów indeksu na dokument. Jeśli nie wysyłasz zapytań na podstawie pola z dużą tablicą lub mapą, wyłącz jego indeksowanie.

Operacje odczytu i zapisu

  • Dokładny maksymalny współczynnik, z jakim aplikacja może aktualizować pojedynczy dokument, zależy w dużym stopniu od obciążenia. Więcej informacji znajdziesz w artykule Aktualizacje pojedynczego dokumentu.

  • Jeśli to możliwe, używaj wywołań asynchronicznych zamiast synchronicznych. Wywołania asynchroniczne minimalizują wpływ opóźnienia. Rozważ na przykład aplikację, która przed wyrenderowaniem odpowiedzi potrzebuje wyniku wyszukiwania dokumentu i wyników zapytania. Jeśli wyszukiwanie i zapytanie nie mają zależności od danych, nie trzeba synchronicznie czekać na zakończenie wyszukiwania przed rozpoczęciem zapytania.

  • Nie używaj przesunięć. Zamiast tego używaj kursorów. Użycie przesunięcia powoduje tylko, że pominięte dokumenty nie są zwracane do aplikacji, ale nadal są 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.

Ponawianie transakcji

Biblioteki Cloud Firestore SDK i biblioteki klienta Cloud Firestore automatycznie ponawiają nieudane transakcje, aby poradzić sobie z przejściowymi błędami. Jeśli aplikacja uzyskuje dostęp Cloud Firestore przez interfejsy API REST lub RPC bezpośrednio zamiast przez bibliotekę SDK, powinna ona implementować ponawianie transakcji, aby zwiększyć niezawodność.

Aktualizacje w czasie rzeczywistym

Sprawdzone metody związane z aktualizacjami w czasie rzeczywistym znajdziesz w artykule Informacje o zapytaniach w czasie rzeczywistym na dużą skalę.

Projektowanie pod kątem skalowania

Te sprawdzone metody opisują, jak unikać sytuacji, które powodują problemy z rywalizacją.

Aktualizacje pojedynczego dokumentu

Podczas projektowania aplikacji zastanów się, jak szybko aktualizuje ona pojedyncze dokumenty. Najlepszym sposobem na określenie wydajności obciążenia jest przeprowadzenie testu obciążenia. Dokładny maksymalny współczynnik, z jakim aplikacja może aktualizować pojedynczy dokument, zależy w dużym stopniu od obciążenia. Czynniki obejmują współczynnik zapisu, rywalizację między żądaniami i liczbę indeksów, których dotyczą problemy.

Operacja zapisu dokumentu aktualizuje dokument i powiązane z nim indeksy, a Cloud Firestore synchronicznie stosuje operację zapisu w kworum replik. Przy wystarczająco wysokich współczynnikach zapisu baza danych zacznie napotykać rywalizację, większe opóźnienie lub inne błędy.

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

Unikaj wysokich współczynników odczytu lub zapisu w przypadku dokumentów, które są blisko siebie w porządku leksykograficznym, ponieważ aplikacja będzie napotykać błędy rywalizacji. Ten problem jest znany jako hotspotting. Aplikacja może napotykać hotspotting, jeśli wykonuje dowolną z tych czynności:

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

    Cloud Firestore przydziela identyfikatory dokumentów za pomocą algorytmu rozpraszania. Jeśli tworzysz nowe dokumenty za pomocą automatycznych identyfikatorów dokumentów, nie powinny występować problemy z hotspottingiem podczas zapisywania.

  • Tworzy nowe dokumenty z dużą szybkością w kolekcji z niewielką liczbą dokumentów.

  • Tworzy nowe dokumenty z polem, które rośnie monotonicznie, np. sygnaturą czasową, z bardzo dużą szybkością.

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

  • Zapisuje dane w bazie danych z bardzo dużą szybkością bez stopniowego zwiększania ruchu.

Unikanie pomijania usuniętych danych

Unikaj zapytań, które pomijają niedawno usunięte dane. Zapytanie może pominąć dużą liczbę wpisów indeksu, jeśli wczesne wyniki zapytania zostały niedawno usunięte.

Przykładem obciążenia, które może pominąć wiele usuniętych danych, jest obciążenie, które próbuje znaleźć najstarsze elementy robocze w kolejce. Zapytanie może wyglądać tak:

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 pola created w przypadku wszystkich niedawno usuniętych dokumentów. Spowalnia to zapytania.

Aby poprawić wydajność, użyj metody start_at, aby znaleźć najlepsze miejsce do rozpoczęcia. 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 użyto pola, które rośnie monotonicznie, co jest anty-wzorcem w przypadku wysokich współczynników zapisu.

Zwiększanie ruchu

Powoli zwiększaj ruch do nowych kolekcji lub dokumentów, które są blisko siebie w porządku leksykograficznym , aby dać Cloud Firestore wystarczająco dużo czasu na przygotowanie dokumentów na zwiększony ruch. Zalecamy rozpoczęcie od maksymalnie 500 operacji na sekundę w nowej kolekcji, a następnie zwiększanie ruchu o 50% co 5 minut. Możesz podobnie zwiększać ruch zapisu, ale pamiętaj o Cloud Firestorestandardowych limitach. Upewnij się, że operacje są rozłożone stosunkowo równomiernie w całym zakresie kluczy. Nazywa się to regułą „500/50/5”.

Przenoszenie ruchu do nowej kolekcji

Stopniowe zwiększanie ruchu jest szczególnie ważne, jeśli przenosisz ruch aplikacji z jednej kolekcji do drugiej. Prostym sposobem na przeprowadzenie tej migracji jest odczyt z starej kolekcji, a jeśli dokument nie istnieje, odczyt z nowej kolekcji. Może to jednak spowodować nagły wzrost ruchu do dokumentów, które są blisko siebie w porządku leksykograficznym w nowej kolekcji. Cloud Firestore może nie być w stanie skutecznie przygotować nowej kolekcji na zwiększony ruch, zwłaszcza jeśli zawiera ona niewiele dokumentów.

Podobny problem może wystąpić, jeśli zmienisz identyfikatory dokumentów wielu dokumentów w tej samej kolekcji.

Najlepsza strategia przenoszenia ruchu do nowej kolekcji zależy od modelu danych. Poniżej znajduje się przykład strategii znanej jako odczyty równoległe. Musisz określić, czy ta strategia jest skuteczna w przypadku Twoich danych. Ważnym czynnikiem będzie wpływ kosztów operacji równoległych podczas migracji.

Odczyty równoległe

Aby zaimplementować odczyty równoległe podczas migracji ruchu do nowej kolekcji, najpierw odczytaj dane ze starej kolekcji. Jeśli dokumentu nie ma, odczytaj dane z nowej kolekcji. Wysoki współczynnik odczytów nieistniejących dokumentów może prowadzić do hotspottingu, dlatego stopniowo zwiększaj obciążenie nowej kolekcji. Lepszą strategią jest skopiowanie starego dokumentu do nowej kolekcji, a następnie usunięcie starego dokumentu. Stopniowo zwiększaj liczbę odczytów równoległych, aby mieć pewność, że Cloud Firestore poradzi sobie z ruchem 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, aby wybrać losowy odsetek użytkowników próbujących zapisać nowe dokumenty. Upewnij się, że wynik skrótu identyfikatora użytkownika nie jest zniekształcony przez Twoją funkcję ani przez zachowanie użytkownika.

W międzyczasie uruchom zadanie wsadowe, które skopiuje wszystkie dane ze starych dokumentów do nowej kolekcji. Zadanie wsadowe powinno unikać zapisywania w sekwencyjnych identyfikatorach dokumentów, aby zapobiec powstawaniu hotspotów. Po zakończeniu zadania wsadowego możesz odczytywać dane tylko z nowej kolekcji.

Ulepszeniem tej strategii jest przenoszenie małych partii użytkowników naraz. Dodaj do dokumentu użytkownika pole, które śledzi stan migracji tego użytkownika. Wybierz partię użytkowników do przeniesienia na podstawie skrótu identyfikatora użytkownika. Użyj zadania wsadowego, aby przenieść dokumenty dla tej partii użytkowników, a w przypadku użytkowników w trakcie migracji użyj odczytów równoległych.

Pamiętaj, że nie możesz łatwo cofnąć zmian, chyba że podczas migracji będziesz wykonywać podwójne zapisy zarówno starych, jak i nowych encji. Zwiększy to Cloud Firestore koszty.

Prywatność

  • Unikaj przechowywania informacji poufnych w identyfikatorze projektu w chmurze. Identyfikator projektu w chmurze może być przechowywany dłużej niż projekt.
  • Zgodnie ze sprawdzonymi metodami dotyczącymi zgodności danych zalecamy, aby nie przechowywać informacji poufnych w nazwach dokumentów i nazwach pól dokumentów.

Zapobiegaj nieautoryzowanemu dostępowi

Zapobiegaj nieautoryzowanym operacjom w bazie danych za pomocą Cloud Firestore Security Rules. Na przykład użycie reguł może zapobiec sytuacji, w której złośliwy użytkownik wielokrotnie pobiera całą bazę danych.

Więcej informacji o korzystaniu z Cloud Firestore Security Rules.