Spis treści
- Czym jest skalowalność: skalowanie pionowe i poziome
- Monolit czy mikrousługi: prosta reguła decyzji
- Techniki, które dają najwięcej: bezstanowość, cache, kolejki
- Skalowanie bazy danych
- Chmura i automatyczne skalowanie
- Monitorowanie i testy obciążeniowe
- Skalowalna architektura systemu na start: plan w pięciu krokach
- Skalowalność to też kod i zespół
- FAQ
Skalowalna architektura systemu to taka, w której wzrost liczby użytkowników lub danych obsługuje się przez dodanie zasobów, a nie przez przepisywanie aplikacji. W większości firmowych systemów nie wymaga to od razu mikrousług. Wystarczy dobrze zbudowana aplikacja, która nie trzyma stanu na serwerze, korzysta z cache i kolejek, ma przemyślaną bazę danych i monitoring. Poniżej opisuję, jak podejmuję te decyzje i kiedy warto iść dalej.
Same pojęcia, takie jak skalowanie poziome czy mikrousługi, niewiele mówią decydentowi. Dlatego obok nich pokazuję techniki, które w praktyce dają najwięcej, i proste reguły, według których wybieram rozwiązanie.
Czym jest skalowalność: skalowanie pionowe i poziome
Skalowalność to zdolność systemu do obsługi rosnącego obciążenia bez utraty wydajności, przez zwiększenie zasobów. Są dwa podstawowe sposoby:
- Skalowanie pionowe: mocniejszy serwer, więcej pamięci, szybszy procesor i dyski. Proste, nie wymaga zmian w aplikacji, ale ma sufit i jeden punkt awarii.
- Skalowanie poziome: więcej serwerów, między które rozkłada się ruch. Nie ma takiego sufitu i daje odporność na awarię jednej maszyny, ale aplikacja musi być na to przygotowana.
W praktyce zaczyna się od skalowania pionowego, bo jest najtańsze w pracy zespołu, a architekturę projektuje się tak, żeby przejście na poziome było możliwe bez przebudowy. To jest sedno skalowalności: nie budować na zapas, ale nie zamykać sobie drogi.
Monolit czy mikrousługi: prosta reguła decyzji
Dla większości systemów firmowych zaczynam od dobrze podzielonego monolitu, czyli jednej aplikacji z wyraźnymi modułami. Mikrousługi rozważam dopiero wtedy, gdy nad systemem pracuje kilka niezależnych zespołów albo jedna część systemu ma zupełnie inne obciążenie niż reszta.
Monolit jest prostszy we wdrażaniu, testowaniu i utrzymaniu, a dobrze zbudowany skaluje się poziomo bez problemu: uruchamia się kilka kopii tej samej aplikacji za load balancerem. Mikrousługi pozwalają skalować i wdrażać każdą usługę osobno, ale w zamian wymagają orkiestracji, na przykład Kubernetes, rozproszonego monitoringu, obsługi błędów komunikacji między usługami i większego zespołu. To koszt, który ma sens przy dużej skali, a przy małej spowalnia rozwój.
Moja reguła jest taka: jeśli nie potrafisz wskazać konkretnej części systemu, która potrzebuje osobnego skalowania lub osobnego cyklu wdrożeń, mikrousługi rozwiązują problem, którego nie masz. Przy nowym produkcie dochodzi jeszcze niepewność zakresu, o czym piszę w tekście o tym, jak zaplanować MVP.
Techniki, które dają najwięcej: bezstanowość, cache, kolejki
Zanim system będzie potrzebował nowej architektury, zwykle wystarczy kilka technik, które pozwalają obsłużyć wielokrotnie większy ruch na tej samej aplikacji. To od nich zaczynam każdą rozmowę o wydajności.
- Bezstanowa aplikacja: sesje, pliki i dane tymczasowe trzymane poza serwerem aplikacji, na przykład w Redis i w magazynie plików. Wtedy każdą kopię aplikacji można dodać lub wyłączyć bez utraty danych użytkowników.
- Load balancer: rozdziela ruch między kopie aplikacji i odcina tę, która przestała odpowiadać.
- Cache: wyniki kosztownych zapytań i fragmenty stron zapamiętane w pamięci. Najtańszy sposób na odciążenie bazy danych.
- Kolejki i przetwarzanie w tle: wysyłka maili, generowanie dokumentów, synchronizacja z ERP czy import plików nie blokują użytkownika, tylko trafiają do kolejki i wykonują się asynchronicznie.
- CDN: zdjęcia, skrypty i pliki statyczne serwowane z sieci serwerów bliżej użytkownika, a nie z serwera aplikacji.
Kolejki mają jeszcze jedną zaletę: kiedy zewnętrzny system, na przykład ERP, chwilowo nie odpowiada, zadania czekają i wykonują się później, zamiast kończyć się błędem przed klientem.
Skalowanie bazy danych
Baza danych najczęściej staje się wąskim gardłem, bo trudniej ją powielić niż aplikację. Zanim sięgnie się po złożone techniki, warto sprawdzić rzeczy proste: brakujące indeksy, zapytania pobierające za dużo danych i raporty liczone na tej samej bazie, która obsługuje zamówienia.
Gdy to nie wystarcza, są trzy główne drogi:
- Replikacja: kopie bazy na kolejnych serwerach przejmują zapytania do odczytu, a zapis trafia do głównej. Dobrze pasuje do systemów, w których odczytów jest dużo więcej niż zapisów.
- Partycjonowanie i sharding: podział danych na części według klucza, na przykład klienta lub okresu. Skuteczny przy bardzo dużych zbiorach, ale komplikuje zapytania i raporty.
- Bazy NoSQL: przydatne do konkretnych zadań, takich jak dzienniki zdarzeń czy dane o zmiennej strukturze, ale rzadko jako zamiennik bazy relacyjnej dla zamówień i faktur.
W systemach, które buduję, podstawą jest zwykle PostgreSQL albo MySQL z replikacją do odczytu i Redis jako cache. Ta kombinacja obsługuje bardzo duży ruch, zanim pojawi się potrzeba shardingu.
Chmura i automatyczne skalowanie
Chmura pozwala dodawać i odejmować serwery automatycznie, zależnie od ruchu, i płacić za faktyczne użycie. To duża zaleta przy sezonowych szczytach, ale działa tylko wtedy, gdy aplikacja jest bezstanowa i uruchamia się szybko.
Automatyczne skalowanie nie zastąpi dobrej architektury. Aplikacja, która przy każdym żądaniu wykonuje setki zapytań do bazy, po prostu zwiększy rachunek, a baza i tak będzie wąskim gardłem. Czy chmura opłaca się w ogóle, zależy od charakteru obciążenia, o czym piszę w tekście czy warto inwestować w chmurę.
Monitorowanie i testy obciążeniowe
Skalowalności nie da się ocenić bez pomiaru. Monitoring powinien pokazywać czas odpowiedzi, liczbę błędów, obciążenie serwerów i bazy oraz długość kolejek, a alerty informować, zanim użytkownicy zauważą problem. Do tego służą narzędzia takie jak Prometheus i Grafana, uzupełnione analizą logów.
Przed spodziewanym wzrostem ruchu, na przykład kampanią albo sezonem, robię test obciążeniowy na środowisku zbliżonym do produkcyjnego. Pokazuje on, która część systemu pierwsza nie wytrzyma, i pozwala poprawić ją wcześniej. Ustalenia z monitoringu i testów warto zapisać w umowie utrzymaniowej, o czym piszę przy temacie umowa SLA na utrzymanie systemu.
Skalowalna architektura systemu na start: plan w pięciu krokach
Przy nowym systemie nie projektuję pod ruch, którego jeszcze nie ma, tylko tak, żeby późniejszy wzrost nie wymagał przebudowy. W praktyce sprowadza się to do kilku decyzji podjętych na początku:
- Określ, jakiego obciążenia spodziewasz się w ciągu dwóch lat i które części systemu będą najbardziej używane.
- Zbuduj aplikację jako bezstanową, z sesjami i plikami poza serwerem aplikacji.
- Wydziel do kolejki wszystko, co nie musi wykonać się natychmiast przy kliknięciu użytkownika.
- Zaprojektuj bazę z myślą o indeksach i oddziel raporty od bazy obsługującej bieżące operacje.
- Od pierwszego dnia zbieraj metryki i logi, żeby wiedzieć, kiedy zbliżasz się do granicy.
Te kroki prawie nie podnoszą kosztu budowy, a oszczędzają wiele miesięcy pracy, gdy system zacznie rosnąć.
Skalowalność to też kod i zespół
Architektura na schemacie niewiele daje, jeśli kod jest trudny do zmiany. Regularne przeglądy kodu, optymalizacja zapytań do bazy, testy automatyczne i porządek w zależnościach decydują o tym, czy system da się rozwijać przez kolejne lata. Gdy tego zabraknie, narasta dług, który w końcu blokuje każdą zmianę, co opisałem w tekście o tym, jak rozpoznać dług technologiczny.
Architekturę dobiera się też do zespołu. Rozwiązanie, którego nikt w firmie ani u wykonawcy nie umie utrzymać, jest ryzykiem, a nie przewagą.
Jeśli Twój system zaczyna zwalniać, zacznij od pomiaru: gdzie dokładnie rośnie czas odpowiedzi i co jest obciążone. Najczęściej okaże się, że wystarczy cache, kolejka albo kilka indeksów, a skalowalna architektura systemu jest bliżej, niż wynika z prezentacji o mikrousługach.
FAQ
Kiedy przejść z monolitu na mikrousługi?
Gdy nad systemem pracuje kilka niezależnych zespołów albo konkretna część systemu ma zupełnie inne obciążenie lub cykl wdrożeń niż reszta. Jeśli nie umiesz wskazać takiej części, mikrousługi zwykle dodają kosztu i złożoności bez korzyści.
Co to jest aplikacja bezstanowa?
To aplikacja, która nie przechowuje sesji ani plików użytkowników na swoim serwerze, tylko w zewnętrznym magazynie, na przykład w Redis. Dzięki temu można uruchomić wiele jej kopii i dodawać lub wyłączać serwery bez utraty danych.
Czy chmura sama rozwiąże problemy z wydajnością?
Nie. Automatyczne skalowanie dodaje serwery, ale jeśli aplikacja ma źle napisane zapytania albo trzyma stan na serwerze, zwiększy się głównie rachunek. Najpierw trzeba usunąć wąskie gardła w kodzie i bazie danych.
Jak sprawdzić, czy system wytrzyma większy ruch?
Najlepiej przez test obciążeniowy na środowisku zbliżonym do produkcyjnego, z realistycznym scenariuszem użytkowników. Test pokazuje, która część systemu pierwsza zwalnia, a monitoring pozwala potem obserwować te miejsca na produkcji.