W tym dokumencie znajdziesz wskazówki dotyczące skalowania aplikacji bezserwerowej, która obsługuje tysiące operacji na sekundę lub setki tysięcy użytkowników jednocześnie. Ten dokument zawiera zaawansowane tematy, które pomogą Ci dogłębnie zrozumieć system. Jeśli dopiero zaczynasz korzystać z Cloud Firestore, zapoznaj się z krótkim przewodnikiem.
Cloud Firestore oraz pakiety SDK Firebase na urządzenia mobilne i do internetu zapewniają zaawansowany model tworzenia aplikacji bezserwerowych, w których kod po stronie klienta ma bezpośredni dostęp do bazy danych. Pakiety SDK umożliwiają klientom nasłuchiwanie aktualizacji danych w czasie rzeczywistym. Dzięki aktualizacjom w czasie rzeczywistym możesz tworzyć responsywne aplikacje, które nie wymagają infrastruktury serwerowej. Uruchomienie aplikacji jest bardzo proste, ale warto poznać ograniczenia systemów, które składają się na Cloud Firestore Dzięki temu Twoja aplikacja bezserwerowa będzie się dobrze skalować i działać, gdy ruch wzrośnie.
Więcej informacji o skalowaniu aplikacji znajdziesz w sekcjach poniżej.
Wybierz lokalizację bazy danych blisko użytkowników
Ten schemat przedstawia architekturę aplikacji działającej w czasie rzeczywistym:
Gdy aplikacja działająca na urządzeniu użytkownika (mobilnym lub internetowym) nawiązuje
połączenie z Cloud Firestore, połączenie jest kierowane do serwera frontendu
Cloud Firestore w tym samym
regionie, w którym znajduje się Twoja baza danych. Jeśli na przykład
Twoja baza danych znajduje się w regionie us-east1, połączenie jest kierowane do
Cloud Firestore frontendu również w regionie us-east1. Te połączenia są
długotrwałe i pozostają otwarte, dopóki nie zostaną wyraźnie zamknięte przez aplikację. Frontend odczytuje dane z bazowych Cloud Firestore systemów przechowywania.
Odległość między fizyczną lokalizacją użytkownika a Cloud Firestore lokalizacją bazy danych wpływa na opóźnienie odczuwane przez użytkownika. Na przykład użytkownik w Indiach, którego aplikacja komunikuje się z bazą danych w regionie Google Cloud w Ameryce Północnej, może zauważyć, że aplikacja działa wolniej i mniej płynnie niż w przypadku, gdyby baza danych znajdowała się bliżej, np. w Indiach lub w innej części Azji.
Projektowanie z myślą o niezawodności
Te tematy wpływają na niezawodność aplikacji lub ją poprawiają:
Włącz tryb offline
Pakiety SDK Firebase zapewniają trwałość danych offline. Jeśli aplikacja na urządzeniu użytkownika nie może połączyć się z Cloud Firestore, nadal można jej używać, ponieważ działa ona na podstawie danych zapisanych w pamięci podręcznej. Dzięki temu użytkownicy mają dostęp do danych nawet wtedy, gdy mają problemy z połączeniem internetowym lub całkowicie tracą dostęp na kilka godzin lub dni. Więcej informacji o trybie offline znajdziesz w artykule Włączanie danych offline.
Automatyczne ponawianie
Pakiety SDK Firebase zajmują się ponawianiem operacji i przywracaniem zerwanych połączeń. Pomaga to radzić sobie z przejściowymi błędami spowodowanymi ponownym uruchomieniem serwerów lub problemami z siecią między klientem a bazą danych.
Wybór między lokalizacjami regionalnymi i wieloregionalnymi
Wybór między lokalizacjami regionalnymi i wieloregionalnymi wiąże się z kilkoma kompromisami. Główna różnica polega na sposobie replikacji danych. To wpływa na gwarancje dostępności aplikacji. Instancja wieloregionalna zapewnia większą niezawodność i trwałość danych, ale wiąże się z wyższymi kosztami.
System zapytań w czasie rzeczywistym
Zapytania w czasie rzeczywistym, nazywane też detektorami zrzutu, umożliwiają aplikacji nasłuchiwanie zmian w bazie danych i otrzymywanie powiadomień o niskim opóźnieniu, gdy tylko dane się zmienią. Aplikacja może uzyskać ten sam wynik, okresowo sprawdzając bazę danych pod kątem aktualizacji, ale często jest to wolniejsze, droższe i wymaga więcej kodu. Przykłady konfigurowania i używania zapytań w czasie rzeczywistym znajdziesz w artykule Otrzymywanie aktualizacji w czasie rzeczywistym. W sekcjach poniżej znajdziesz szczegółowe informacje o tym, jak działają detektory zrzutu, oraz opis niektórych sprawdzonych metod skalowania zapytań w czasie rzeczywistym przy zachowaniu wydajności.
Wyobraź sobie 2 użytkowników, którzy łączą się z Cloud Firestore za pomocą aplikacji do obsługi wiadomości utworzonej za pomocą jednego z pakietów SDK na urządzenia mobilne.
Klient A zapisuje w bazie danych, aby dodać i zaktualizować dokumenty w kolekcji o nazwie chatroom:
collection chatroom:
document message1:
from: 'Sparky'
message: 'Welcome to Cloud Firestore!'
document message2:
from: 'Santa'
message: 'Presents are coming'
Klient B nasłuchuje aktualizacji w tej samej kolekcji za pomocą detektora zrzutu. Klient B otrzymuje natychmiastowe powiadomienie, gdy ktoś utworzy nową wiadomość. Ten schemat przedstawia architekturę detektora zrzutu:
Gdy klient B połączy detektor zrzutu z bazą danych, nastąpi ta sekwencja zdarzeń:
- Klient B otwiera połączenie z Cloud Firestore i rejestruje
detektor, wywołując funkcję
onSnapshot(collection("chatroom"))za pomocą pakietu SDK Firebase. Ten detektor może być aktywny przez wiele godzin. - Frontend Cloud Firestore wysyła zapytanie do bazowego systemu przechowywania aby uruchomić zbiór danych. Wczytuje cały zbiór wyników pasujących dokumentów. Nazywamy to zapytaniem o sondowanie. Następnie system ocenia reguły zabezpieczeń Firebase bazy danych , aby sprawdzić, czy użytkownik ma dostęp do tych danych. Jeśli użytkownik jest autoryzowany, baza danych zwraca mu dane.
- Zapytanie klienta B przechodzi w tryb nasłuchiwania. Detektor rejestruje się w obsłudze subskrypcji i czeka na aktualizacje danych.
- Klient A wysyła teraz operację zapisu, aby zmodyfikować dokument.
- Baza danych zatwierdza zmianę dokumentu w swoim systemie przechowywania.
- System zatwierdza tę samą aktualizację w wewnętrznym dzienniku zmian. Dziennik zmian ustala ścisłą kolejność zmian.
- Dziennik zmian z kolei rozsyła zaktualizowane dane do puli obsługi subskrypcji.
- Wykonuje się dopasowywanie zapytań odwrotnych , aby sprawdzić, czy zaktualizowany dokument pasuje do obecnie zarejestrowanych detektorów zrzutu. W tym przykładzie dokument pasuje do detektora zrzutu klienta B. Jak sama nazwa wskazuje, dopasowywanie zapytań odwrotnych można traktować jako zwykłe zapytanie do bazy danych, ale wykonywane w odwrotnej kolejności. Zamiast przeszukiwać dokumenty w celu znalezienia tych, które pasują do zapytania, skutecznie przeszukuje zapytania w celu znalezienia tych, które pasują do przychodzącego dokumentu. Po znalezieniu dopasowania system przekazuje dany dokument do detektorów zrzutu. Następnie system ocenia reguły zabezpieczeń Firebase bazy danych, aby upeśnić się, że dane otrzymują tylko autoryzowani użytkownicy.
- System przekazuje aktualizację dokumentu do pakietu SDK na urządzeniu klienta B i uruchamia wywołanie zwrotne
onSnapshot. Jeśli włączona jest trwałość lokalna, pakiet SDK stosuje aktualizację również do pamięci podręcznej.
Kluczowym elementem skalowalności Cloud Firestore's jest zwielokrotnienie wyjściowe z dziennika zmian do modułów obsługi subskrypcji i serwerów frontendu. Zwielokrotnienie wyjściowe umożliwia efektywne propagowanie pojedynczej zmiany danych w celu obsługi milionów zapytań w czasie rzeczywistym i połączonych użytkowników. Dzięki uruchamianiu wielu replik wszystkich tych komponentów w różnych strefach (lub w przypadku wdrożenia wieloregionalnego – w różnych regionach) Cloud Firestore osiąga wysoką dostępność i skalowalność.
Warto zauważyć, że wszystkie operacje odczytu wykonywane przez pakiety SDK na urządzenia mobilne i do internetu są zgodne z powyższym modelem. Wykonują one zapytanie o sondowanie, a następnie przechodzą w tryb nasłuchiwania, aby zachować gwarancje spójności. Dotyczy to również detektorów w czasie rzeczywistym, wywołań służących do pobierania dokumentu i zapytań jednorazowych. Pobieranie pojedynczych dokumentów i zapytania jednorazowe można traktować jako krótkotrwałe detektory zrzutu, które mają podobne ograniczenia dotyczące wydajności.
Stosowanie sprawdzonych metod skalowania zapytań w czasie rzeczywistym
Aby projektować skalowalne zapytania w czasie rzeczywistym, stosuj te sprawdzone metody.
Duży ruch związany z zapisem w systemie
W tej sekcji dowiesz się, jak system reaguje na rosnącą liczbę żądań zapisu.
Dzienniki zmian Cloud Firestore, które obsługują zapytania w czasie rzeczywistym , automatycznie skalują się w poziomie wraz ze wzrostem ruchu związanego z zapisem. Gdy szybkość zapisu w bazie danych przekroczy możliwości pojedynczego serwera, dziennik zmian zostanie podzielony na kilka serwerów, a przetwarzanie zapytań zacznie korzystać z danych z wielu obsługi subskrypcji zamiast z jednego. Z perspektywy klienta i pakietu SDK wszystko to jest przejrzyste i nie wymaga żadnych działań ze strony aplikacji. Ten schemat pokazuje, jak skalują się zapytania w czasie rzeczywistym:
Automatyczne skalowanie umożliwia zwiększenie ruchu związanego z zapisem bez ograniczeń, ale wraz ze wzrostem ruchu system może potrzebować więcej czasu na odpowiedź. Aby uniknąć tworzenia hotspotu zapisu, postępuj zgodnie z zaleceniami reguły 5-5-5. Key Visualizer to przydatne narzędzie do analizowania hotspotów zapisu.
Wiele aplikacji ma przewidywalny wzrost organiczny, który Cloud Firestore może obsłużyć bez żadnych środków ostrożności. Jednak zadania wsadowe, takie jak importowanie dużego zbioru danych, mogą zbyt szybko zwiększyć liczbę zapisów. Podczas projektowania aplikacji pamiętaj, skąd pochodzi ruch związany z zapisem.
postępuj zgodnie z regułą 5-5-5.Interakcje między zapisami i odczytami
System zapytań w czasie rzeczywistym można traktować jako potok łączący operacje zapisu z czytelnikami. Za każdym razem, gdy dokument zostanie utworzony, zaktualizowany lub usunięty, zmiana jest propagowana z systemu przechowywania do obecnie zarejestrowanych detektorów. Struktura dziennika zmian Cloud Firestore gwarantuje silną spójność, co oznacza, że aplikacja nigdy nie otrzymuje powiadomień o aktualizacjach, które są nieuporządkowane w porównaniu z momentem, w którym baza danych zatwierdziła zmiany danych. Upraszcza to tworzenie aplikacji, ponieważ eliminuje przypadki brzegowe związane ze spójnością danych.
Ten połączony potok oznacza, że operacja zapisu powodująca hotspoty lub konflikty blokad może negatywnie wpływać na operacje odczytu. Gdy operacje zapisu nie powiodą się lub zostaną ograniczone, odczyt może się zatrzymać w oczekiwaniu na spójne dane z dziennika zmian. Jeśli tak się stanie w Twojej aplikacji, możesz zauważyć zarówno powolne operacje zapisu, jak i powiązane z nimi powolne czasy odpowiedzi na zapytania. Aby uniknąć tego problemu, należy unikać hotspotów.
Małe dokumenty i operacje zapisu
Podczas tworzenia aplikacji z detektorami zrzutu zwykle chcesz, aby użytkownicy szybko dowiadywali się o zmianach danych. Aby to osiągnąć, staraj się, aby wszystko było małe. System może bardzo szybko przesyłać małe dokumenty z dziesiątkami pól. Przetwarzanie większych dokumentów z setkami pól i dużymi ilościami danych trwa dłużej.
Podobnie, aby utrzymać niskie opóźnienie, preferuj krótkie i szybkie operacje zatwierdzania i zapisu. Duże partie mogą zwiększyć przepustowość z perspektywy osoby zapisującej, ale mogą też wydłużyć czas powiadomienia dla detektorów zrzutu. Często jest to sprzeczne z intuicją w porównaniu z innymi systemami baz danych, w których można używać grupowania w celu zwiększenia wydajności.
Wydajne detektory
Wraz ze wzrostem szybkości zapisu w bazie danych Cloud Firestore dzieli przetwarzanie danych na wiele serwerów. Algorytm fragmentowania Cloud Firestore próbuje umieścić dane z tej samej kolekcji lub grupy kolekcji na tym samym serwerze dziennika zmian. System stara się zmaksymalizować możliwą przepustowość zapisu przy jednoczesnym utrzymaniu jak najmniejszej liczby serwerów zaangażowanych w przetwarzanie zapytania.
Jednak niektóre wzorce mogą nadal prowadzić do nieoptymalnego działania detektorów zrzutu. Jeśli na przykład Twoja aplikacja przechowuje większość danych w jednej dużej kolekcji, detektor może potrzebować połączenia z wieloma serwerami, aby otrzymać wszystkie potrzebne dane. Dotyczy to również sytuacji, gdy zastosujesz filtr zapytania. Połączenie z wieloma serwerami zwiększa ryzyko wolniejszych odpowiedzi.
Aby uniknąć tych wolniejszych odpowiedzi, zaprojektuj schemat i aplikację tak, aby system mógł obsługiwać detektory bez konieczności przechodzenia do wielu różnych serwerów. Najlepiej może być podzielić dane na mniejsze kolekcje o mniejszej szybkości zapisu.
Jest to podobne do myślenia o zapytaniach dotyczących wydajności w relacyjnej bazie danych, które wymagają pełnego skanowania tabeli. W relacyjnej bazie danych zapytanie, które wymaga pełnego skanowania tabeli, jest odpowiednikiem detektora zrzutu, który obserwuje kolekcję o dużej liczbie zmian. Może działać wolniej niż zapytanie, które baza danych może obsłużyć za pomocą bardziej szczegółowego indeksu. Zapytanie z bardziej szczegółowym indeksem jest jak detektor zrzutu, który obserwuje pojedynczy dokument lub kolekcję, która zmienia się rzadziej. Aby lepiej zrozumieć działanie i potrzeby swojego przypadku użycia, przeprowadź test obciążenia aplikacji.
Szybkie zapytania o sondowanie
Kluczowym elementem responsywnych zapytań w czasie rzeczywistym jest też zapewnienie, że zapytanie o sondowanie służące do uruchamiania danych jest szybkie i wydajne. Gdy nowy detektor zrzutu połączy się po raz pierwszy, musi wczytać cały zbiór wyników i wysłać go na urządzenie użytkownika. Powolne zapytania sprawiają, że aplikacja działa mniej responsywnie. Dotyczy to na przykład zapytań, które próbują odczytać wiele dokumentów, lub zapytań, które nie używają odpowiednich indeksów.
W pewnych okolicznościach detektor może też przejść z trybu nasłuchiwania do trybu sondowania. Dzieje się to automatycznie i jest niewidoczne dla pakietów SDK i Twojej aplikacji. Te warunki mogą spowodować przejście do trybu sondowania:
- System ponownie równoważy dziennik zmian z powodu zmian obciążenia.
- Hotspoty powodują nieudane lub opóźnione zapisy w bazie danych.
- Przejściowe ponowne uruchomienia serwera tymczasowo wpływają na detektory.
Jeśli zapytania o sondowanie są wystarczająco szybkie, tryb sondowania staje się niewidoczny dla użytkowników aplikacji.
Preferowanie długotrwałych detektorów
Otwieranie i utrzymywanie detektorów przy życiu tak długo, jak to możliwe, jest często najbardziej opłacalnym sposobem tworzenia aplikacji korzystającej z Cloud Firestore. W przypadku korzystania z Cloud Firestore opłaty są naliczane za dokumenty zwracane do aplikacji a nie za utrzymywanie otwartego połączenia. Długotrwały detektor zrzutu odczytuje tylko te dane, które są potrzebne do obsługi zapytania przez cały okres jego istnienia. Obejmuje to początkową operację sondowania, a następnie powiadomienia, gdy dane faktycznie się zmienią. Z drugiej strony zapytania jednorazowe ponownie odczytują dane, które mogły się nie zmienić od czasu ostatniego wykonania zapytania przez aplikację.
W przypadkach, gdy aplikacja musi przetwarzać dane z dużą szybkością, detektory zrzutu mogą nie być odpowiednie. Jeśli na przykład Twój przypadek użycia wymaga przesyłania wielu dokumentów na sekundę przez połączenie przez dłuższy czas, lepiej wybrać zapytania jednorazowe wykonywane z mniejszą częstotliwością.
Przyszłe
- Dowiedz się, jak korzystać z detektorów zrzutu.
- Przeczytaj więcej sprawdzonych metod.