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
Unikaj używania zbyt wielu indeksów. Nadmierna liczba indeksów może zwiększyć opóźnienia zapisu i zwiększyć koszty przechowywania wpisów indeksu.
Należy pamiętać, że indeksowanie pól o monotonicznie rosnących wartościach, takich jak znaczniki czasu, może prowadzić do powstawania punktów aktywnych , które wpływają na opóźnienia w aplikacjach o dużej szybkości odczytu i zapisu.
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 , a nie 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 wysokich współczynników odczytu lub zapisu w celu leksykograficznego zamykania dokumentów, 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 .