Iść w mikrousługi czy nie, oto jest pytanie

Systemy rozproszone funkcjonują już w świecie od jakiegoś czasu. Założenie tworzenia aplikacji na dużą skalę i o dużej dostępności jest z nami od lat 70-tych. Od czasów bańki internetowej około roku 1995 nieprzerwanie szliśmy coraz bardziej w tym kierunku, nie oglądając się za siebie. Aż w końcu, na początku drugiej dekady XXI wieku, nastała era mikrousług. Rozwiązanie ochrzczone jako „fine grained SOA” przez Adriana Cockrofta, byłego dyrektora Netfliksa ds. systemów chmurowych, zdominowało świat programistów.

Teraz, po niemal 10 latach, systemy oparte na mikrousługach to coś zupełnie powszechnego, na czym pracuje wielu z nas. Ale czy każdy patrząc na nie rzeczywiście widzi systemy rozproszone, a nie garść niezależnych, zorkiestrowanych mikro-aplikacji? Z jakimi z pozoru niespodziewanymi problemami mamy do czynienia na co dzień?

Czym są systemy rozproszone?

Są to systemy, których komponenty działają w jednej sieci i komunikują się poprzez przekazywanie wiadomości. Komponenty współdziałają w tym samym czasie, są od siebie niezależne i nie są zsynchronizowane. W zależności od ich implementacji, komponenty w systemie rozproszonym mogą być homogeniczne lub heterogeniczne. Ich sens opiera się na głównym założeniu, zgodnie z którym, aby poradzić sobie z większym problemem, najłatwiej jest wykorzystać wiele urządzeń o niewielkiej mocy obliczeniowej, podzielić go na mniejsze kawałki i wykonać polecenie równolegle. Przykładem systemów rozproszonych są systemy oparte na architekturze zorientowanej na usługi, gdzie funkcje (usługi) dostarczane są przez aplikację za pośrednictwem jej osobnych komponentów, komunikujących się w sieci. Każda usługa ma swoją zhermetyzowaną funkcjonalność.

Czym są systemy mikrousługowe?

Jest to podgrupa systemów opartych na architekturze zorientowanej na usługi, w których aplikacja składa się z częściowo zależnych, drobnojednostkowych usług komunikujących się za pomocą lekkich protokołów. Zadaniem każdej mikrousługi jest enkapsulacja jednej warstwy, domeny lub funkcjonalności systemu, zazwyczaj zachowując przy tym możliwie jak najwięcej niezależności od pozostałych elementów. Zwyczajowo wiążą się one ze znaczącymi zaletami nad monolitami, o których powiemy za moment, aczkolwiek mają też one swoje wady i komplikacje, których nie należy pomijać.

Główne zalety podejścia opartego na mikrousługach

Modularność

Mikrousługi są z natury niezależne. Wiedzą tylko to, czego potrzebują lub co jest dla nich ważne. Stawiając na ich maksymalną hermetyczność, każdą usługę można zapisać w odrębnym języku, uniezależniając ją od pozostałych. Ta cecha czyni je prostszymi w zrozumieniu i rozwijaniu, a także ułatwia ich testowanie. W przypadku awarii usługi tylko niewielka część aplikacji przestaje działać, co można naprawić i przywrócić niezależnie od reszty systemu. Ogólnie rzecz biorąc, im bardziej modularne staje się środowisko mikrousług, tym lepiej funkcjonuje.

Skalowalność

Za modularnością, a jednocześnie w jakiś sposób w jej efekcie, skalowalność to skutek niezależności związanej z wdrażaniem i uruchamianiem każdej mikrousługi. Większe tymczasowe obciążenie pojedynczego punktu w systemie niekoniecznie musi prowadzić do spadku wydajności, o ile ten obciążony punkt jest skalowalny poziomo. Nawet gdy owa skalowalność nie jest nieograniczona, zarządzanie i rozwój będą dużo łatwiejsze, ponieważ skalowana usługa jest niewielka i prosta, przynajmniej w teorii.

Integracja

Rzadko kiedy przeprowadza się wdrożenie wszystkich aplikacji na raz, zwłaszcza nie tych, które wymagają architektury mikrousługowej. Ich modularność pozwala na niezależne budowanie konsekutywnych komponentów i integrowanie ich z resztą systemu. Jest to zazwyczaj prostsze do wykonania od wdrożenia warstwy/komponentu w monolicie. Ponadto wszelkie przyszłe zmiany można wdrożyć i uruchomić w ramach pojedynczej mikrousługi.

Dystrybucja i równoległa rozbudowa

W konsekwencji tego drugiego, po zaprojektowaniu i specyfikacji, części systemu można rozwijać niezależnie. Obejmuje to także jednoczesne rozbudowywanie różnych usług i pozwala na rozproszenie wdrożenia między zespoły w różnych lokalizacjach. Jest to szczególnie korzystne w przypadku aplikacji wielkoskalowych i większych organizacji zarządzających kilkoma zespołami pracującymi nad jednym systemem.

Główne wady podejścia opartego na mikrousługach

Architektura i komunikacja systemowa

Sposób, w jaki komponenty systemu komunikują się ze sobą jest często skomplikowany. W wielu przypadkach nie wystarczy odczekać. Zamiast tego konieczne będzie wdrożenie kolejki, strumienia lub podziału na tematy. Prowadzi to do większej złożoności systemu, lecz w większości przypadków również zwiększa jego odporność.

Zasoby, infrastruktura i konserwacja

Biorąc pod uwagę liczbę dodatkowych komponentów infrastrukturalnych, które mogą być potrzebne zgodnie z powyższym punktem, faktyczna ilość zasobów niezbędna do ich funkcjonowania jest bardzo wysoka. Główne elementy, o które trzeba zadbać dla każdej usługi to repozytorium, konfiguracja, pipeline CI/CD i skrypty wdrożeniowe. Ponadto należy tutaj uwzględnić konserwację, ponieważ bardziej skomplikowana infrastruktura wiąże się z trudnościami z modyfikacją i utrzymywaniem operacji.

Testowanie

Nawet jeśli mikrousługi sprawiają, że testowanie komponentów staje się łatwiejsze, należy wykonywać dodatkowe testy, by zapewnić jakość, a zwłaszcza testy integracyjne i testy end-to-end. Celem testów integracyjnych jest obnażenie defektów w interakcjach pomiędzy mikrousługami. Tutaj trudność wiąże się nie tylko z samą liczbą integracji między komponentami, jaką trzeba przetestować, ale także z aspektem technicznym, jakim jest utworzenie środowiska umożliwiającego testowanie. Testy end-to-end dla aplikacji opartych na mikrousługach w dużej mierze zależy od specyfikacji i wdrożenia. Wciąż jednak nie będzie to proste zadanie, jeśli weźmiemy pod uwagę wielość komponentów systemowych i przepływów danych.

Rozbudowa, debugowanie i śledzenie

Tworząc komponent, programista zazwyczaj chce wdrożyć go lokalnie lub na jakimś środowisku, połączyć z debuggerem i debugować na żywo. W przypadku mikrousług jest to o wiele trudniejsze ze względu na liczbę komponentów, przez które przepływają dane, skomplikowaną infrastrukturę oraz ograniczenia środowisk wdrożeniowych. To samo tyczy się śledzenia i protokołowania. Na szczęście teraz dysponujemy już urządzeniami pozwalającymi na śledzenie przepływu pomiędzy mikrousługami.

Małe przedsiębiorstwa

Zazwyczaj uznaje się, że systemy mikrousługowe to coś, w co mniejsze przedsiębiorstwa nie powinny się angażować. Niektóre narzędzia próbują podchodzić do tematu, ale biorąc pod uwagę wiele małych aplikacji, asynchroniczne wdrażanie, kwestie infrastrukturalne i kompleksowe testy, koszt często przekracza możliwości niewielkich organizacji.

Transakcje

Dla aplikacji monolitycznych transakcje to z reguły proste zadanie, które można wdrożyć z łatwością. Jeśli chodzi zaś o mikrousługi, transakcje stają się nieco bardziej skomplikowane. Jedno możliwe podejście opiera się na implementacji rozproszonego mechanizmu transakcyjnego. To jednak bardzo skomplikowane, kosztowne i często nie dające się skalować rozwiązanie. Wśród korzyści należy wymienić maksymalizację spójności w całym systemie. Inne podejście to budowa systemu, gdzie spójność osiągnięta będzie później. W tym przypadku zgadzamy i przygotowujemy się na tymczasowe braki spójności w systemie, które zazwyczaj dotyczyć będą danych. Druga opcja najczęściej okazuje się o wiele lepsza w kontekście skalowania i aplikacji o wysokiej przepustowości, aczkolwiek jest bardziej podatna na błędy i wymaga pisania dbałego kodu z racji obecnych niespójności.

Refaktoryzacja

Wprowadzanie zmian w kodzie w systemie mikrousługowym może się różnie skończyć. Sprawa jest prosta jeśli zmiana jest wewnętrzna i nie wykracza poza poziom pojedynczej mikrousługi. Jeśli jednak zmiana dotyczy całego systemu, pojawia się kilka problemów. Po pierwsze, zmianę należy wprowadzić jednocześnie na wielu komponentach, między którymi należy zapewnić kontrakty. Następnie wdrożenie zmian należy przeprowadzić w skoordynowany sposób, co często wymaga wyłączenia całego systemu.

Najczęstsze błędy dotyczące mikrousług

Odpowiedni podział

Istnieją dwa często występujące, lecz błędne podejścia dotyczące wytyczania właściwych podziałów w systemie opartym na mikrousługach. Pierwszy z nich to przypadki, gdzie pojedyncza warstwa systemu rozdzielna jest na wiele komponentów. Kluczowe jest, aby ograniczyć udostępnianie informacji systemowych tylko do niezbędnych komponentów i łączyć dane ze sobą w jak najluźniejszy sposób. Drugim błędem są sytuacje, gdzie pojedynczy komponent ma zbyt dużo wiedzy, świadomości systemu lub odpowiedzialności. Wówczas stanowi to jasny znak, że można by go podzielić na dwa mniejsze, bardziej wyspecjalizowane komponenty.

Świadomość skalowania

Chociaż skalowanie powinno należeć do głównych zalet systemu opartego na mikrousługach, cecha ta zostaje często pominięta, a mikrousługi zostają skonstruowane w sposób uniemożliwiający skalowanie. Dzieję się tak np. wtedy, gdy „kluczowa” mikrousługa zostaje wdrożona i połączona ze wszystkimi innymi częściami. Wówczas staje się ona wąskim gardłem i punktem podatności na awarię w systemie.

Ogólna świadomość architektury

Przy wdrażaniu mikrousług nie wystarczy podzielić i zaenkapsulować logiki, powiązać ze sobą części i przejść do działania. Trzeba też pochylić się nad przepływem danych, rozwiązać kwestie spójności, zagwarantować dostępność i zarządzić podziałem architektury. To zdecydowanie najbardziej wymagający aspekt systemów opartych na mikrousługach, a mimo tego umyka on wielu osobom decydującym się na obranie tej ścieżki.

Końcowe refleksje

Szum wokół mikrousług nie przestaje rosnąć. Ten artykuł nie ma na celu nikogo przestraszyć ani zniechęcić. Ma on za zadanie pokazać, że wybór mikrousług wiąże się z konsekwencjami. W wielu przypadkach przeważać nad nimi będzie szereg zalet wynikających z tego podejścia. Jednak w równie wielu przypadkach trzymanie się starego, ale dobrego i prostego monolitu byłoby zupełnie wystarczające.

Poznaj mageek of j‑labs i daj się zadziwić, jak może wyglądać praca z j‑People!

Skontaktuj się z nami