Sprawdzone metody dotyczące Cloud Firestore

Wymienione tu sprawdzone metody mogą przydać się przy tworzeniu aplikacji korzystającej z Cloud Firestore.

Lokalizacja bazy danych

Podczas tworzenia instancji bazy danych wybierz lokalizację bazy danych najbliżej użytkowników i zasobów obliczeniowych. Duże przeskoki sieciowe są bardziej podatne na błędy i zwiększają czas oczekiwania na odpowiedź.

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

Wybierz lokalizację regionalną, aby obniżyć koszty, skrócić czas oczekiwania na zapis, jeśli aplikacja jest wrażliwa na czas oczekiwania, lub współlokować zasoby z innymi zasobami GCP.

Identyfikatory dokumentów

  • Unikaj stosowania dokumentów o identyfikatorach . 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ą powodować występowanie hotspotów, które skracają czas oczekiwania.

Nazwy pól

  • Unikaj stosowania w nazwach pól tych znaków, ponieważ wymagają one dodatkowych znaków zmiany znaczenia:

    • . okres
    • [ otwierający nawias
    • ] zamykający nawias
    • Gwiazdka: *
    • Grawis `

Indeksy

Zmniejsz opóźnienia zapisu

Głównym czynnikiem wpływającym na opóźnienia zapisu jest zwielokrotnienie indeksu. Oto sprawdzone metody pozwalające ograniczyć zachmurzenie indeksów:

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

  • Zmniejsz liczbę dokumentów w transakcji. W przypadku tworzenia dużej liczby dokumentów rozważ użycie narzędzia do zapisu zbiorczego zamiast samodzielnego zapisującego dane wsadowe.

Zwolnienia z indeksu

W przypadku większości aplikacji do zarządzania indeksami możesz korzystać z automatycznego indeksowania oraz linków z komunikatami o błędach. Możesz jednak dodać wykluczenia z jednego pola w tych przypadkach:

Zgłoszenie Opis
Duże pola ciągów

Jeśli masz pole ciągu znaków, które często zawiera wartości długich ciągów, których nie używasz do zapytań, możesz zmniejszyć koszty przechowywania, wykluczając to pole z indeksowania.

Duża szybkość 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. sygnatura czasowa), maksymalna szybkość zapisu w kolekcji wynosi 500 zapisów na sekundę. Jeśli nie wykonujesz zapytań na podstawie pola z wartościami sekwencyjnymi, możesz wykluczyć pole z indeksowania, aby ominąć ten limit.

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

Pola TTL

Jeśli używasz zasad TTL (czasu życia), pamiętaj, że pole TTL musi zawierać sygnaturę czasową. Indeksowanie według pól czasu TTL jest domyślnie włączone i może mieć wpływ na wydajność przy wyższym odsetku ruchu. Zalecaną metodą jest dodanie wykluczeń jednego pola do pól TTL.

Duże pola tablicowe lub mapowania

Duże pola tablic lub mapy mogą zbliżać się do limitu 40 000 wpisów indeksu na dokument. Jeśli nie wysyłasz zapytań na podstawie dużej tablicy lub pola mapy, wyklucz je z indeksowania.

Operacje odczytu i zapisu

  • Dokładna maksymalna częstotliwość, z jaką aplikacja może aktualizować pojedynczy dokument, zależy w dużym stopniu od obciążenia. Więcej informacji znajdziesz w artykule Aktualizacje pojedynczego dokumentu.

  • Zamiast wywołań synchronicznych używaj wywołań asynchronicznych, gdy są dostępne. Wywołania asynchroniczne minimalizują wpływ opóźnień. Rozważmy na przykład aplikację, która przed wyrenderowaniem odpowiedzi potrzebuje wyników wyszukiwania dokumentów i zapytań. Jeśli wyszukiwanie i zapytanie nie mają zależności danych, nie ma potrzeby synchronicznego oczekiwania na zakończenie wyszukiwania przed zainicjowaniem zapytania.

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

Ponowne próby transakcji

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

Powiadomienia w czasie rzeczywistym

Sprawdzone metody związane z aktualizacjami w czasie rzeczywistym znajdziesz w artykule Omówienie zapytań w czasie rzeczywistym na dużą skalę.

Projektowanie z myślą o skali

Poniżej znajdziesz sprawdzone metody, które pomogą Ci uniknąć sytuacji, w których mogą powstać problemy związane z rywalizacją.

Aktualizacje pojedynczego dokumentu

Podczas projektowania aplikacji weź pod uwagę to, jak szybko aktualizuje ona pojedyncze dokumenty. Najlepszym sposobem scharakteryzowania wydajności zadania jest wykonanie testów obciążenia. Dokładna maksymalna częstotliwość, 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 dotyczy problem.

Operacja zapisu dokumentu aktualizuje dokument i wszystkie powiązane indeksy, a Cloud Firestore synchronicznie stosuje operację zapisu do kworum replik. Przy odpowiednio wysokiej szybkości zapisu w bazie danych zaczną występować rywalizacje, większe opóźnienia i inne błędy.

Wysoka szybkość odczytu, zapisu i usuwania dokumentów obejmująca wąski zakres dokumentów

Unikaj wysokich szybkości odczytu i zapisu w leksykograficznie zamkniętych dokumentach, ponieważ spowoduje to wystąpienie błędów rywalizacji. Ten problem nazywamy hotspotem hotspot i w jego przypadku mogą występować takie problemy, jeśli:

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

    Cloud Firestore przydziela identyfikatory dokumentów za pomocą algorytmu punktowego. Jeśli tworzysz nowe dokumenty przy użyciu automatycznych identyfikatorów dokumentów, nie powinny wystąpić hotspoty przy zapisach.

  • Szybko tworzy nowe dokumenty w kolekcji z niewielką liczbą dokumentów.

  • Tworzy bardzo szybko nowe dokumenty z monotonicznie rosnącym polem, takim jak sygnatura czasowa.

  • Usuwa dokumenty z kolekcji z dużą częstotliwością.

  • Zapisuje dane do bazy danych z bardzo dużą częstotliwością bez stopniowego zwiększania ruchu.

Unikaj pomijania usuniętych danych

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

Przykładem zadania, które może być wymagało pominięcia dużej ilości usuniętych danych, jest zadanie znajdowania najstarszych elementów roboczych 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 dotyczące pola created we wszystkich niedawno usuniętych dokumentach. Spowalnia to zapytania.

Aby zwiększyć skuteczność, użyj metody start_at, by znaleźć najlepsze miejsce na początek. 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 przykładzie powyżej użyto monotonicznie rosnącego pola, które stanowi antywzorzec zapewniający dużą częstotliwość zapisu.

Zwiększanie natężenia ruchu

Stopniowo zwiększaj ruch do nowych kolekcji lub leksykograficznie zamknij dokumenty, aby dać Cloud Firestore wystarczająco dużo czasu na przygotowanie dokumentów na wzrost natężenia ruchu. Zalecamy, aby zacząć od maksymalnie 500 operacji na sekundę do nowego zbioru, a następnie co 5 minut zwiększać ruch o 50%. W podobny sposób możesz 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. Jest to tzw. reguła „500/50/5”.

Przenoszenie ruchu do nowej kolekcji

Stopniowe zwiększanie jest szczególnie ważne, jeśli przenosisz ruch w aplikacji z jednej kolekcji do drugiej. Prostym sposobem na obsługę tej migracji jest odczyt ze starej kolekcji, a jeśli dokument nie istnieje, następnie odczyt z nowej kolekcji. Może to jednak spowodować gwałtowny wzrost natężenia ruchu leksykograficznego do zamykania dokumentów w nowej kolekcji. Cloud Firestore może nie być w stanie efektywnie przygotować nowej kolekcji na zwiększony ruch, zwłaszcza gdy zawiera ona niewiele dokumentów.

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

Najlepsza strategia przenoszenia ruchu do nowego zbioru zależy od modelu danych. Poniżej znajduje się przykładowa strategia nazywana odczytami równoległymi. Musisz sprawdzić, czy ta strategia jest skuteczna w przypadku Twoich danych. Trzeba też wziąć pod uwagę wpływ na koszty operacji równoległych podczas migracji.

Odczyty równoległe

Aby wdrożyć równoległe odczyty podczas migracji ruchu do nowej kolekcji, odczytaj najpierw dane ze starej kolekcji. Jeśli brakuje dokumentu, odczytaj go z nowej kolekcji. Duża liczba odczytów nieistniejących dokumentów może prowadzić do „hotspotingu”, dlatego pamiętaj, aby stopniowo zwiększać obciążenie nowej kolekcji. Lepszą strategią jest skopiowanie starego dokumentu do nowej kolekcji, a następnie usunięcie starego dokumentu. Stopniowo zwiększaj tempo odczytów równoległych, aby mieć pewność, że Cloud Firestore może obsługiwać ruch do nowej kolekcji.

Możliwą strategią stopniowego zwiększania liczby odczytów lub zapisów w nowej kolekcji jest użycie deterministycznego hasza identyfikatora użytkownika w celu wybrania losowego odsetka użytkowników próbujących tworzyć nowe dokumenty. Dopilnuj, aby wynik haszowania identyfikatora użytkownika nie został zniekształcony przez Twoją funkcję ani przez zachowanie użytkownika.

Tymczasem uruchom zadanie wsadowe, które skopiuje wszystkie dane ze starych dokumentów do nowej kolekcji. Aby uniknąć tworzenia hotspotów, Twoje zadanie wsadowe powinno unikać zapisywania w sekwencyjnych identyfikatorach dokumentów. Po zakończeniu zadania wsadowego będziesz mieć możliwość odczytu tylko z nowej kolekcji.

Ulepszeniem tej strategii jest migracja niewielkich grup użytkowników naraz. Dodaj do dokumentu użytkownika pole, które będzie śledzić stan migracji danego użytkownika. Wybierz grupę użytkowników do migracji, używając skrótu identyfikatora użytkownika. Użyj zadania wsadowego, aby przenieść dokumenty tej grupy użytkowników, a następnie użyj odczytów równoległych dla użytkowników w trakcie migracji.

Pamiętaj, że nie można łatwo wycofać zmiany, dopóki na etapie migracji nie wykonasz podwójnego zapisu zarówno starych, jak i nowych jednostek. Spowoduje to wzrost kosztów Cloud Firestore.

Prywatność

  • Unikaj przechowywania informacji poufnych w identyfikatorze projektu Cloud. Identyfikator projektu Cloud może być przechowywany po okresie jego trwania.
  • Zgodnie ze sprawdzoną metodą zachowania zgodności z danymi odradzamy przechowywanie informacji poufnych w nazwach dokumentów i polach pól dokumentów.

Zapobieganie nieautoryzowanemu dostępowi

Reguły zabezpieczeń Cloud Firestore pomogą Ci zapobiec nieautoryzowanym operacjam w bazie danych. Reguły pozwalają na przykład uniknąć sytuacji, w której złośliwy użytkownik wielokrotnie pobiera całą bazę danych.

Dowiedz się więcej o używaniu reguł zabezpieczeń Cloud Firestore.