Fiszki Online Systemy rozproszone (Preview)
Darmowy podgląd 15 z 52 dostępnych pytań
Fundamenty i wzorce
Czym jest system rozproszony i czym różni się od architektury klient-serwer?
System rozproszony to aplikacja złożona z wielu współpracujących ze sobą komponentów uruchomionych na różnych maszynach, komunikujących się przez sieć. Może to być wiele różnych aplikacji albo wiele replik tej samej aplikacji, które razem realizują jedną logiczną usługę (np. wyszukiwarkę czy platformę sprzedażową).
W klasycznej architekturze klient-serwer podział jest prosty: klient wysyła żądania, a serwer je obsługuje. System rozproszony idzie dalej — sama "strona serwerowa" składa się z wielu współpracujących procesów rozsianych po różnych maszynach.
Główne różnice:
- Niezawodność — odpowiednio zaprojektowany system rozproszony jest z natury bardziej odporny na awarie, bo brak pojedynczego punktu, którego awaria kładzie całość.
- Skalowalność — można skalować niezależnie poszczególne komponenty zamiast całej aplikacji.
- Złożoność — w zamian za te zalety płacimy znacznie wyższym kosztem projektowania, budowy i debugowania. Wymagania inżynierskie są wyraźnie wyższe niż przy aplikacjach jednomaszynowych.
Jakie korzyści daje stosowanie wzorców projektowych przy budowie systemów rozproszonych?
Wzorzec to ogólny plan organizacji systemu, niezależny od konkretnej technologii czy aplikacji — w przeciwieństwie do przepisu na instalację konkretnej bazy NoSQL czy stosu technologicznego. Korzyści są trzy:
- Uczenie się na cudzych błędach — wzorce kodyfikują rozwiązania, do których inni doszli poprzez kosztowne pomyłki. Nie musisz mieć osobistego doświadczenia z danym typem systemu, by zbudować go solidnie.
- Wspólny język — gdy obie strony rozmowy wiedzą, czym jest "sidecar", nie tracą czasu na ustalanie nazewnictwa i mogą od razu dyskutować o szczegółach rozwiązania.
- Reużywalne komponenty — zidentyfikowanie powtarzalnych wzorców pozwala zaimplementować je raz (np. jako obraz kontenera z interfejsem HTTP) i wielokrotnie używać w różnych językach i kontekstach, co dodatkowo podnosi jakość, bo wspólny kod jest intensywnie testowany.
Wzorce jednowęzłowe
Na czym polega wzorzec sidecar?
Sidecar to wzorzec jednowęzłowy złożony z dwóch kontenerów współplanowanych w jednej grupie. Pierwszy to kontener aplikacji zawierający główną logikę. Drugi to kontener sidecar, którego rolą jest rozszerzanie i ulepszanie kontenera aplikacji — często bez jego wiedzy.
Oba kontenery dzielą szereg zasobów: część systemu plików, nazwę hosta i sieć, a także inne przestrzenie nazw. Dzięki temu sidecar może np. nasłuchiwać na tym samym localhost, na którym serwuje aplikacja.
Klasyczny przykład: starsza usługa serwuje wyłącznie nieszyfrowany HTTP na localhost, a dołożony sidecar (np. serwer proxy) terminuje HTTPS na zewnętrznym adresie i przekazuje ruch lokalnie do aplikacji. W ten sposób modernizujemy usługę bez przebudowy jej kodu.
Podaj przykłady zastosowania wzorca sidecar.
Sidecar nie służy tylko do adaptacji starszych aplikacji. Typowe zastosowania:
- Dodanie HTTPS do starszej usługi — sidecar terminuje szyfrowanie i proxuje ruch do aplikacji nasłuchującej lokalnie na nieszyfrowanym porcie.
- Dynamiczna konfiguracja — kontener menedżera konfiguracji pobiera zmiany przez API, zapisuje je w dzielonym katalogu i sygnalizuje aplikacji konieczność przeładowania (np. przez sygnał czy nadpisanie pliku).
- Modularne narzędzia introspekcji — kontener typu "top" współdzielący przestrzeń PID może raportować zużycie zasobów wszystkich procesów aplikacji przez spójny interfejs, dołączany automatycznie do wszystkich wdrożeń.
- Prosta platforma PaaS — sidecar synchronizujący kod z repozytorium Git w pętli, połączony z serwerem auto-przeładowującym aplikację, daje wdrożenie "push to deploy".
Kluczowa zaleta: sidecar jest modularny i reużywalny, więc raz zbudowany przyspiesza tworzenie wielu różnych aplikacji.
↑ Powrót na góręNa czym polega parametryzacja kontenerów i dlaczego jest ważna dla reużywalności?
Parametryzacja to potraktowanie kontenera jak funkcji w programie: każdy parametr to wejście, które dostosowuje generyczny kontener do konkretnej sytuacji. Bez parametrów sidecar terminujący SSL byłby bezużyteczny — potrzebuje przynajmniej nazwy certyfikatu i portu aplikacji, do której proxuje.
Parametry przekazuje się zwykle przez zmienne środowiskowe lub przez wiersz poleceń. Wewnątrz kontenera prosty skrypt startowy czyta te zmienne i dostosowuje pliki konfiguracyjne lub samą aplikację.
Parametryzacja jest najważniejszą rzeczą, jaką można zrobić, by kontener stał się modularny i reużywalny w wielu aplikacjach. Bez niej każdy nowy przypadek użycia wymagałby budowy osobnego, dedykowanego obrazu.
↑ Powrót na góręWzorce serwujące
Czym jest usługa bezstanowa i dlaczego replikujemy ją za load balancerem?
Usługa bezstanowa (stateless) to taka, która do poprawnego działania nie wymaga zapisanego stanu między żądaniami. W najprostszej postaci nawet pojedyncze żądania tego samego użytkownika mogą trafiać do różnych instancji. Przykłady to serwery treści statycznych czy warstwy pośredniczące agregujące odpowiedzi z wielu backendów.
Najprostszy wzorzec rozproszony to usługa replikowana za load balancerem: skalowalna liczba identycznych serwerów, z których każdy może obsłużyć każde żądanie, a przed nimi load balancer (round-robin lub z przypisaniem sesji).
Replikacja daje dwie rzeczy: redundancję (awaria jednej repliki nie kładzie usługi) oraz skalowanie poziome (więcej użytkowników obsługujemy, dodając repliki).
↑ Powrót na góręDlaczego nawet mała usługa potrzebuje co najmniej dwóch replik?
Chodzi o dotrzymanie SLA dostępności. Usługa "trzech dziewiątek" (99,9%) dopuszcza około 1,4 minuty niedostępności dziennie.
Z jedną instancją oznacza to, że nawet jeśli aplikacja nigdy się nie zawiesza, każde wdrożenie nowej wersji musisz zmieścić w 1,4 minuty na dobę. A jeśli wdrażasz częściej — np. co godzinę w modelu continuous delivery — musiałbyś wdrożyć w ~3,6 sekundy, by nie przekroczyć budżetu niedostępności.
Zamiast tej heroicznej walki wystarczą dwie repliki za load balancerem. Podczas wdrożenia (albo w razie awarii jednej repliki) użytkowników obsługuje druga replika i nikt nie zauważy, że coś się działo. Dlatego dwie repliki to praktyczne minimum dla usługi o wysokiej dostępności.
↑ Powrót na góręCzym różni się readiness probe od health/liveness probe?
To dwa różne sygnały dla orkiestratora i load balancera:
| Sonda | Pytanie, na które odpowiada | Reakcja systemu |
|---|---|---|
| Health / liveness | Czy aplikacja żyje i czy nie trzeba jej zrestartować? | Restart kontenera |
| Readiness | Czy aplikacja jest gotowa obsługiwać żądania? | Włączenie/wyłączenie z puli load balancera |
Rozróżnienie ma sens, bo wiele aplikacji żyje, ale nie jest jeszcze gotowa — potrzebuje czasu na inicjalizację: połączenie z bazą, załadowanie wtyczek czy pobranie plików z sieci. Taki kontener nie powinien być restartowany (żyje), ale też nie powinien dostawać ruchu (nie jest gotów). Projektując usługę replikowaną, warto udostępnić osobny URL realizujący sprawdzenie gotowości.
↑ Powrót na góręCzym jest session tracking (przypisanie sesji) i kiedy go potrzebujemy?
Domyślnie ruch rozkłada się na wszystkie repliki, co daje równe obciążenie i odporność na awarie. Czasem jednak chcemy, by żądania danego użytkownika trafiały zawsze do tej samej repliki — np. gdy cache'ujemy dane użytkownika w pamięci (wyższy hit rate) albo interakcja jest długotrwała i utrzymuje stan między żądaniami.
To właśnie session tracking. Zwykle realizuje się go, haszując adresy źródłowy i docelowy i używając wyniku do wyboru serwera. Dopóki adresy się nie zmieniają, żądania trafiają do tej samej repliki.
Ograniczenie: śledzenie po IP działa wewnątrz klastra, ale słabo z zewnętrznymi adresami z powodu NAT — wtedy lepiej śledzić sesję na poziomie aplikacji (np. ciasteczko czy nagłówek HTTP). Często stosuje się też consistent hashing, by zmiana liczby replik minimalnie przemapowywała użytkowników.
↑ Powrót na góręFunkcje i przetwarzanie sterowane zdarzeniami
Czym jest FaaS i czym różni się od pojęcia "serverless"?
FaaS (Function as a Service) to model, w którym kod istnieje tymczasowo, by obsłużyć pojedyncze żądanie lub zareagować na zdarzenie. Funkcje są uruchamiane w odpowiedzi na dyskretne zdarzenia i mają zwykle ograniczony czas działania.
FaaS bywa nazywany "serverless", ale warto rozróżnić oba pojęcia:
- Serverless — nie widzisz serwerów; pojęcie szersze. Np. wielodzierżawczy orkiestrator kontenerów (container-as-a-service) jest serverless, ale nie jest sterowany zdarzeniami.
- Event-driven — sterowany zdarzeniami. Open source'owy FaaS na własnym, administrowanym klastrze fizycznym jest sterowany zdarzeniami, ale nie jest serverless.
Zrozumienie tej różnicy pomaga ocenić, czy dla danej aplikacji właściwe jest podejście sterowane zdarzeniami, serverless, czy oba. W praktyce FaaS jest zwykle komponentem szerszej architektury, a nie kompletnym rozwiązaniem.
↑ Powrót na góręJakie są zalety FaaS?
Korzyści FaaS są przede wszystkim po stronie dewelopera:
- Krótka droga od kodu do działającej usługi — nie ma artefaktu do zbudowania czy wypchnięcia poza sam kod źródłowy, więc przejście z kodu na laptopie do działania w chmurze jest banalnie proste.
- Automatyczne zarządzanie i skalowanie — wraz ze wzrostem ruchu powstaje więcej instancji funkcji; awaria aplikacji lub maszyny skutkuje automatycznym restartem na innej maszynie.
- Bardzo granularny budulec — funkcje są bezstanowe, więc systemy z nich budowane są z natury bardziej modularne i odprzęgnięte niż jeden monolityczny plik wykonywalny.
To samo silne odprzęgnięcie bywa jednak również słabością — co prowadzi do wyzwań FaaS.
↑ Powrót na góręWybór właściciela i elekcja mastera
Czym jest elekcja mastera i kiedy jest potrzebna?
W wielu systemach istnieje pojęcie własności — konkretny proces "posiada" konkretne zadanie lub fragment przestrzeni kluczy (jak w systemach shardowanych). Na pojedynczym serwerze własność jest prosta: wystarczy wewnątrzprocesowa blokada, bo tylko jedna aplikacja ją ustanawia.
Problem w tym, że ograniczenie własności do jednej aplikacji ogranicza skalowalność (zadania nie da się replikować) i niezawodność (awaria czyni zadanie niedostępnym). Gdy potrzebujesz własności w systemie rozproszonym, musisz zbudować mechanizm jej ustanawiania.
Elekcja mastera to proces wyboru, która z replik jest właścicielem (masterem), oraz wyboru nowego mastera, gdy poprzedni padnie. W typowym scenariuszu master numer 1 pada, master przejmuje replika 3, a gdy replika 1 wraca, replika 3 pozostaje masterem. Ustanowienie rozproszonej własności bywa najtrudniejszą i najważniejszą częścią projektu niezawodnego systemu.
↑ Powrót na góręKiedy wystarczy wzorzec singleton zamiast elekcji mastera?
Najprostsza forma własności to jedna replika — skoro działa tylko jedna instancja, niejawnie posiada wszystko, bez żadnej elekcji. To upraszcza aplikację i wdrożenie kosztem dostępności.
Uruchomiony na orkiestratorze singleton ma jednak całkiem przyzwoity uptime: kontener jest restartowany po awarii/zawieszeniu w kilka sekund (to często ~3–4 dziewiątki), a po awarii maszyny przenoszony na inną (np. ~5 minut przestoju).
Głównym ograniczeniem bywają wdrożenia: z singletonem nie da się trzymać starej i nowej wersji jednocześnie, więc na czas aktualizacji usługa znika. Jeśli wdrożenie trwa 2 minuty i robisz je co godzinę, nie utrzymasz nawet jednej dziewiątki.
Wniosek: dla wielu aplikacji (np. asynchronicznego przetwarzania w tle) prostota singletonu jest warta tego kompromisu. Dopiero gdy wymagana jest wysoka dostępność (cztery+ dziewiątki), opłaca się wiele replik z wyborem jednego właściciela. Częścią projektu systemu rozproszonego jest rozpoznanie, kiedy "rozproszony" oznacza zbędną złożoność.
↑ Powrót na góręWsadowe wzorce obliczeniowe
Czym jest system kolejki zadań (work queue) i jakie są jego założenia?
Kolejka zadań to najprostsza forma przetwarzania wsadowego. Jest zbiór jednostek pracy, z których każda jest całkowicie niezależna od pozostałych i może być przetworzona bez interakcji z innymi. Celem systemu jest zwykle zapewnienie, że każda jednostka zostanie przetworzona w określonym czasie; liczbę workerów skaluje się w górę i w dół zależnie od obciążenia.
Większość logiki kolejki jest niezależna od konkretnej pracy, więc da się ją współdzielić jako reużywalne kontenery. W generycznej, kontenerowej kolejce wyróżnia się dwa interfejsy:
- Interfejs kontenera-źródła — dostarcza strumień jednostek do przetworzenia (np. lista plików w storage, kolejka w pub/sub). To zwykle ambasador adaptujący konkretne źródło do generycznego API.
- Interfejs kontenera-workera — wie, jak faktycznie przetworzyć pojedynczą jednostkę pracy.
Sam menedżer kolejki odpowiada za śledzenie, które jednostki przetworzono, a które jeszcze nie. Na orkiestratorze (np. przez obiekt typu Job uruchamiany do skutku) można zbudować taką kolejkę nawet bez własnego magazynu stanu.
↑ Powrót na góręJak dobrać liczbę workerów, by kolejka zadań była stabilna?
Kluczowe są dwie metryki: czas międzyprzybyć (średni odstęp między nowymi jednostkami) i czas przetwarzania jednej jednostki. Warunek stabilności: efektywny czas przetwarzania musi być krótszy niż czas międzyprzybyć.
Trzy przypadki:
- Praca przychodzi co 1 min, przetwarzanie trwa 30 s — system nadąża i odrabia zaległości (przetwarza dwie jednostki na każdą przybyłą).
- Praca co 1 min, przetwarzanie 1 min — system jest "na styk": nadrobi skok, ale nie ma marginesu na trwały wzrost.
- Praca co 1 min, przetwarzanie 2 min — kolejka rośnie bez ograniczeń, a opóźnienia dążą do nieskończoności.
Przy przetwarzaniu równoległym czas przetwarzania dzielimy przez równoległość: 1 min na jednostkę przy 4 workerach to efektywne 15 s, więc system zniesie odstęp ≥16 s. To pozwala zbudować autoskaler: zwiększaj równoległość, aż czas przetwarzania spadnie poniżej czasu międzyprzybyć, i zostaw margines bezpieczeństwa (np. redukuj równoległość tylko do poziomu, przy którym przetwarzanie to ~90% czasu międzyprzybyć).
↑ Powrót na górę