Jak skalować od 1 do 100 000 użytkowników

Wiele startupów przez to przeszło: codziennie rejestrują się tłumy nowych użytkowników, a zespół programistów walczy o utrzymanie działania usługi.

To fajny problem, ale w sieci jest niewiele jasnych informacji na temat ostrożnego skalowania aplikacji internetowej od zera do setek tysięcy użytkowników. Zazwyczaj istnieją rozwiązania przeciwpożarowe lub rozwiązania wąskiego gardła (a często jedno i drugie). Dlatego ludzie używają raczej oklepanych technik, aby przemienić swój amatorski projekt w coś naprawdę poważnego.

Spróbujmy przefiltrować informacje i zapisać podstawowy wzór. Zamierzamy stopniowo skalować naszą nową witrynę do udostępniania zdjęć Graminsta od 1 do 100 000 użytkowników.

Zapiszmy, jakie konkretne działania należy podjąć, gdy widownia wzrośnie do 10, 100, 1000, 10 000 i 100 000 osób.

1 użytkownik: 1 maszyna

Prawie każda aplikacja, czy to strona internetowa, czy aplikacja mobilna, składa się z trzech kluczowych elementów:

  • API
  • baza danych
  • klient (sama aplikacja mobilna lub strona internetowa)

Baza danych przechowuje trwałe dane. Interfejs API obsługuje żądania do i wokół tych danych. Klient przesyła dane do użytkownika.

Doszedłem do wniosku, że dużo łatwiej jest mówić o skalowaniu aplikacji, jeśli z architektonicznego punktu widzenia klient i API są całkowicie od siebie oddzielone.

Kiedy po raz pierwszy zaczynamy budować aplikację, wszystkie trzy komponenty można uruchomić na tym samym serwerze. Pod pewnymi względami jest to podobne do naszego środowiska programistycznego: jeden inżynier obsługuje bazę danych, interfejs API i klienta na tej samej maszynie.

Teoretycznie moglibyśmy wdrożyć go w chmurze na pojedynczej instancji DigitalOcean Droplet lub AWS EC2, jak pokazano poniżej:
Jak skalować od 1 do 100 000 użytkowników
Mając to na uwadze, jeśli w witrynie będzie więcej niż jeden użytkownik, prawie zawsze sensowne jest wydzielenie warstwy bazy danych.

10 użytkowników: przeniesienie bazy danych na osobny poziom

Podział bazy danych na usługi zarządzane takie jak Amazon RDS czy Digital Ocean Managed Database będzie nam dobrze służył przez długi czas. Jest to trochę droższe niż samodzielny hosting na pojedynczej maszynie lub instancji EC2, ale dzięki tym usługom otrzymujesz od razu wiele przydatnych rozszerzeń, które przydadzą się w przyszłości: tworzenie kopii zapasowych w wielu regionach, odczytywanie replik, automatyczne kopie zapasowe i nie tylko.

Tak wygląda teraz system:
Jak skalować od 1 do 100 000 użytkowników

100 użytkowników: przeniesienie klienta na osobny poziom

Na szczęście naszym pierwszym użytkownikom bardzo spodobała się nasza aplikacja. Ruch staje się coraz bardziej stabilny, więc czas przenieść klienta na osobny poziom. Należy zauważyć że separacja encji jest kluczowym aspektem budowania skalowalnej aplikacji. Gdy jedna część systemu otrzymuje większy ruch, możemy ją podzielić, aby kontrolować sposób skalowania usługi w oparciu o określone wzorce ruchu.

Dlatego lubię myśleć o kliencie jako o czymś odrębnym od API. Dzięki temu bardzo łatwo jest myśleć o tworzeniu oprogramowania dla wielu platform: Internetu, Internetu mobilnego, iOS, Androida, aplikacji komputerowych, usług stron trzecich itp. Wszyscy oni są po prostu klientami korzystającymi z tego samego API.

Na przykład teraz nasi użytkownicy najczęściej proszą o wydanie aplikacji mobilnej. Jeśli oddzielisz encje klienta i API, stanie się to łatwiejsze.

Tak wygląda taki system:

Jak skalować od 1 do 100 000 użytkowników

1000 użytkowników: dodaj moduł równoważenia obciążenia

Sprawy mają się dobrze. Użytkownicy Graminsta przesyłają coraz więcej zdjęć. Rośnie także liczba rejestracji. Nasz samotny serwer API ma trudności z nadążeniem za całym ruchem. Potrzebujesz więcej żelaza!

Moduł równoważenia obciążenia to bardzo potężna koncepcja. Kluczową ideą jest to, że przed API umieścimy moduł równoważenia obciążenia, który dystrybuuje ruch do poszczególnych instancji usługi. W ten sposób skalujemy poziomo, co oznacza, że ​​dodajemy więcej serwerów z tym samym kodem, zwiększając liczbę żądań, które możemy obsłużyć.

Zamierzamy umieścić osobne moduły równoważenia obciążenia przed klientem WWW i przed API. Oznacza to, że możesz uruchomić wiele instancji z kodem API i kodem klienta WWW. Moduł równoważenia obciążenia będzie kierować żądania do serwera, który jest mniej obciążony.

Otrzymujemy tutaj kolejną ważną zaletę - redundancję. Kiedy jedna instancja ulegnie awarii (być może zostanie przeciążona lub ulegnie awarii), pozostają inne, które w dalszym ciągu odpowiadają na przychodzące żądania. Gdyby działała tylko jedna instancja, w przypadku awarii cały system uległby awarii.

Moduł równoważenia obciążenia zapewnia również automatyczne skalowanie. Możemy go skonfigurować tak, aby zwiększał liczbę instancji przed szczytowym obciążeniem i zmniejszał ją, gdy wszyscy użytkownicy śpią.

Dzięki modułowi równoważenia obciążenia poziom API można skalować niemal w nieskończoność, po prostu dodając nowe instancje w miarę wzrostu liczby żądań.

Jak skalować od 1 do 100 000 użytkowników

Notatka. W tej chwili nasz system jest bardzo podobny do tego, co od razu oferują firmy PaaS, takie jak Heroku czy Elastic Beanstalk na AWS (dlatego są tak popularne). Heroku umieszcza bazę danych na oddzielnym hoście, zarządza modułem równoważenia obciążenia z automatycznym skalowaniem i umożliwia hostowanie klienta internetowego niezależnie od interfejsu API. To świetny powód, aby używać Heroku do projektów na wczesnym etapie lub start-upów – wszystkie podstawowe usługi otrzymujesz od razu po wyjęciu z pudełka.

10 000 użytkowników: CDN

Być może powinniśmy byli to zrobić od samego początku. Przetwarzanie żądań i akceptowanie nowych zdjęć zaczyna nadmiernie obciążać nasze serwery.

Na tym etapie musisz skorzystać z usługi w chmurze do przechowywania treści statycznych - obrazów, filmów i wielu innych (AWS S3 lub Digital Ocean Spaces). Ogólnie rzecz biorąc, nasz interfejs API powinien unikać obsługi takich rzeczy, jak udostępnianie obrazów i przesyłanie obrazów na serwer.

Kolejną zaletą hostingu w chmurze jest CDN (AWS nazywa ten dodatek Cloudfront, ale wielu dostawców usług przechowywania w chmurze oferuje go od razu po wyjęciu z pudełka). CDN automatycznie buforuje nasze obrazy w różnych centrach danych na całym świecie.

Chociaż nasze główne centrum danych może znajdować się w Ohio, jeśli ktoś poprosi o obraz z Japonii, dostawca chmury wykona kopię i przechowa ją w jego japońskim centrum danych. Następna osoba, która poprosi o ten obraz w Japonii, otrzyma go znacznie szybciej. Jest to ważne, gdy pracujemy z dużymi plikami, takimi jak zdjęcia lub filmy, których pobranie i przesłanie na całą planetę zajmuje dużo czasu.

Jak skalować od 1 do 100 000 użytkowników

100 000 użytkowników: skalowanie warstwy danych

CDN bardzo pomógł: ruch rośnie pełną parą. Słynny bloger wideo Mavid Mobrick właśnie się u nas zarejestrował i opublikował, jak to się mówi, swoją „historię”. Dzięki modułowi równoważenia obciążenia użycie procesora i pamięci na serwerach API jest utrzymywane na niskim poziomie (działa dziesięć instancji API), ale zaczynamy mieć dużo przekroczeń limitu czasu na żądaniach... Skąd biorą się te opóźnienia?

Wgłębiając się nieco w metryki, widzimy, że procesor serwera bazy danych jest obciążony w 80–90%. Jesteśmy na granicy.

Skalowanie warstwy danych jest prawdopodobnie najtrudniejszą częścią równania. Serwery API obsługują żądania bezstanowe, dlatego po prostu dodajemy więcej instancji API. Nos większość bazy danych nie mogą tego zrobić. Porozmawiamy o popularnych systemach zarządzania relacyjnymi bazami danych (PostgreSQL, MySQL itp.).

buforowanie

Jednym z najprostszych sposobów na zwiększenie wydajności naszej bazy danych jest wprowadzenie nowego komponentu: warstwy pamięci podręcznej. Najpopularniejszą metodą buforowania jest magazyn rekordów klucz-wartość w pamięci, taki jak Redis lub Memcached. Większość chmur ma zarządzaną wersję tych usług: Elasticache na AWS i Memorystore na Google Cloud.

Pamięć podręczna jest przydatna, gdy usługa wykonuje wiele powtarzających się wywołań do bazy danych w celu pobrania tych samych informacji. Zasadniczo uzyskujemy dostęp do bazy danych tylko raz, przechowujemy informacje w pamięci podręcznej i nie dotykamy ich ponownie.

Na przykład w naszym serwisie Graminsta za każdym razem, gdy ktoś wejdzie na stronę profilu gwiazdy Mobrik, serwer API odpytuje bazę danych o informacje z jego profilu. To się powtarza i powtarza. Ponieważ informacje o profilu Mobrika nie zmieniają się przy każdym żądaniu, doskonale nadają się do buforowania.

Wyniki z bazy danych w Redis będziemy buforować według klucza user:id z okresem ważności 30 sekund. Teraz, gdy ktoś wejdzie na profil Mobrika, najpierw sprawdzamy Redis, a jeśli dane tam są, po prostu przesyłamy je bezpośrednio z Redis. Teraz żądania do najpopularniejszego profilu w serwisie praktycznie nie ładują naszej bazy danych.

Kolejną zaletą większości usług buforowania jest to, że można je łatwiej skalować niż serwery baz danych. Redis ma wbudowany tryb klastra Redis. Podobnie jak moduł równoważenia obciążenia1umożliwia dystrybucję pamięci podręcznej Redis na wielu komputerach (w razie potrzeby na tysiącach serwerów).

Prawie wszystkie aplikacje na dużą skalę korzystają z buforowania; jest to absolutnie integralna część szybkiego API. Szybsze przetwarzanie zapytań i bardziej produktywny kod są ważne, ale bez pamięci podręcznej skalowanie usługi do milionów użytkowników jest prawie niemożliwe.

Przeczytaj repliki

Gdy ilość zapytań do bazy danych znacznie wzrosła, możemy jeszcze jedną rzeczą, którą możemy zrobić, jest dodanie replik odczytu w systemie zarządzania bazami danych. Dzięki opisanym powyżej usługom zarządzanym można to zrobić jednym kliknięciem. Odczytana replika pozostanie aktualna w głównej bazie danych i będzie dostępna dla instrukcji SELECT.

Oto nasz system teraz:

Jak skalować od 1 do 100 000 użytkowników

Kolejne kroki

W miarę dalszego skalowania aplikacji będziemy nadal oddzielać usługi, aby skalować je niezależnie. Na przykład, jeśli zaczniemy korzystać z Websockets, wówczas sensownym będzie ściągnięcie kodu przetwarzającego Websockets do osobnej usługi. Możemy umieścić go na nowych instancjach za naszym własnym modułem równoważenia obciążenia, który może skalować w górę i w dół w oparciu o otwarte połączenia Websockets i niezależnie od liczby żądań HTTP.

Będziemy także w dalszym ciągu walczyć z ograniczeniami na poziomie bazy danych. Na tym etapie nadszedł czas na przestudiowanie partycjonowania i fragmentowania bazy danych. Obydwa podejścia wymagają dodatkowego obciążenia, ale umożliwiają skalowanie bazy danych niemal w nieskończoność.

Chcemy także zainstalować usługę monitorującą i analityczną, taką jak New Relic czy Datadog. Pomoże Ci to zidentyfikować powolne zapytania i zrozumieć, gdzie potrzebne są ulepszenia. W miarę skalowania chcemy skupić się na znajdowaniu wąskich gardeł i eliminowaniu ich — często korzystając z niektórych pomysłów z poprzednich sekcji.

Źródła informacji

Inspiracją do tego wpisu był jeden z moje ulubione posty o wysokiej skalowalności. Chciałem, aby artykuł był nieco bardziej szczegółowy dla początkowych etapów projektów i oddzielił go od jednego dostawcy. Koniecznie przeczytaj, jeśli interesuje Cię ten temat.

Przypisy

  1. Chociaż pod względem rozkładu obciążenia w wielu instancjach jest podobny, podstawowa implementacja klastra Redis bardzo różni się od modułu równoważenia obciążenia. [powrót]

Jak skalować od 1 do 100 000 użytkowników

Źródło: www.habr.com

Dodaj komentarz