Mikroserwisy i Spring Cloud. Wprowadzenie

Historia branży informatycznej to historia odkrywania na nowo istniejących rozwiązań. Wybierzcie sobie trzy dowolne buzzwordy, jakie królowały na konferencjach na przestrzeni ostatnich kilku lat, a po bardziej szczegółowym zgłębieniu tematu najprawdopodobniej okaże się, że reprezentowane przez nie koncepty nie są niczym nowym i istniały w świadomości programistów na długo przed tym, jak branża spopularyzowała i zgloryfikowała je na wszelkie możliwe sposoby. Architektura mikroserwisowa nie jest tutaj wyjątkiem. Można bowiem o niej myśleć jako o następcy SOA (Service Oriented Architecture) powstałym na drodze ewolucji sterowanej chęcią wykorzenienia z SOA elementów, które ograniczały możliwości tego modelu.

Czym jest MSA?

Architektura mikroserwisowa to podejście, w którym aplikacja tworzona jest jako zbiór niewielkich, autonomicznych, skupionych na wykonywaniu konkretnych zadań serwisów, współpracujących ze sobą w celu dostarczenia niezbędnej z punktu widzenia klienta funkcjonalności. Rozbijmy tę definicję na części.

Niewielkie

Nie ma uniwersalnej miary, która pozwoliłaby z pewnością określić czy dany serwis jest mały, duży, a może w sam raz. Rozmiar w tym kontekście jest pojęciem względnym. Bardzo podoba mi się natomiast to, co na ten temat napisał Sam Newman w książce Building Microservices. Twierdzi on, że jeżeli nad kodem danego serwisu jest w stanie zapanować jeden mały zespół, to najprawdopodobniej wszystko jest w porządku.

Autonomiczne

Mikroserwisy powinny być od siebie niezależne, przy czym wyznacznikiem niezależności jest tutaj możliwość dokonania zmian i zredeployowania mikroserwisu bez konieczności modyfikacji pozostałych mikroserwisów w systemie. W praktyce oznacza to, że mikroserwisy nie powinny wiedzieć nawzajem o swoich szczegółach implementacyjnych, a w swej współpracy opierać się jedynie na dobrze zdefiniowanych interfejsach.

Skupione na wykonywaniu konkretnych zadań

Jest to nic innego jak przeniesienie zasady jednej odpowiedzialności (single responsibility principle) na grunt mikroserwisów. Dla przypomnienia – SRP głosi, że dany moduł (w naszym przypadku mikroserwis) powinien być odpowiedzialny tylko za jedną funkcjonalność dostarczaną przez system i, że ta funkcjonalność powinna być całkowicie w tym module zamknięta.

Współpracujące ze sobą

Ta część definicji nie wymaga głębszego komentarza. Chodzi oczywiście o wzajemną komunikację mikroserwisów i wzajemne wykorzystywanie dostarczanych przez nie funkcjonalności. Warto jedynie nadmienić, że komunikacja winna być oparta o lekkie protokoły (jak np. HTTP), nieograniczające spektrum możliwych do zintegrowania z nimi technologii.

Zalety

Podejście mikroserwisowe - jeżeli dobrze zaaplikowane - niesie ze sobą szereg korzyści. Należą do nich m.in.:

Skalowalność

Dzięki „rozbiciu” aplikacji na mikroserwisy mamy możliwość skalowania tylko tych komponentów, które stanowią wąskie gardło systemu. Jest to całkowite przeciwieństwo skalowania znanego z aplikacji monolitycznych, w których to operacji tej musi ulegać całość tworzonego oprogramowania.




Odporność na awarie

Awarie pojedynczych mikroserwisów mogą zostać odizolowane w taki sposób, by nie pociągały za sobą awarii całego systemu. Przykładowo, jeżeli w sklepie internetowym z powodu błędu w kodzie awarii ulegnie mikroserwis odpowiedzialny za generowanie spersonalizowanych ofert, to możemy na chwilę zrezygnować z tej funkcjonalności. W przypadku monolitu ten sam problem mógłby spowodować całkowite wstrzymanie pracy aplikacji.

Łatwość wprowadzania zmian

Jako, że mikroserwisy komunikują się ze sobą za pomocą dobrze zdefiniowanych interfejsów, to wszelkie zmiany dotyczące ich szczegółów implementacyjnych mogą być wprowadzane w dowolnych momentach życia systemu, niezależnie od pozostałych jego komponentów. Dzięki temu nie trzeba robić deploymentu całej aplikacji w celu wprowadzenia niewielkich poprawek.

Czytelność

Podział na mikroserwisy wymusza na nas konieczność myślenia o systemie jako zbiorze komunikujących się ze sobą jednostek biznesowych. To z kolei przekłada się na lepszą jakość kodu, gdyż musimy z tego powodu myśleć o interfejsach między mikroserwisami, ukrywaniu ich szczegółów implementacyjnych, wymaganych zależnościach – elementach, które w świecie obiektowym pomagają pisać czysty kod. 

Możliwość mieszania technologi

Użycie do komunikacji protokołu niezwiązanego z żadnym konkretnym językiem czy biblioteką (jak np. HTTP) powoduje, że każdy z mikroserwisów może być napisany z użyciem innej technologii. Dzięki temu nie musimy ograniczać się do jednego języka, a każdy komponent może być stworzony za pomocą narzędzi, które najlepiej adresują jego techniczne potrzeby.

Możliwość eksperymentowania

Z powodu ich niewielkich rozmiarów, łatwiejszym staje się eksperymentowanie w kwestii budowy i zasad działania poszczególnych mikroserwisów. Możemy na przykład stworzyć alternatywną wersję jakiegoś mikroserwisu (napisaną w innej technologii, czy z wykorzystaniem innych algorytmów) i „bezboleśnie” podmienić ją w produkcie.

Wady

Biorąc pod uwagę powszechną ostatnio „modę na mikroserwisy” można odnieść wrażenie, że jest to rozwiązanie pozbawione wad. Nic bardziej mylnego! Tworzenie oprogramowania w oparciu o MSA jest zdecydowanie trudniejsze niż tworzenie aplikacji monolitycznych. Problematyczne jest chociażby testowanie takich systemów, ich deployment (o czym świadczy gwałtowny rozwój gałęzi DevOps-owej w branży), obsługa błędów i transakcyjności. Co więcej, utrzymanie architektury mikroserwisowej wymaga bardzo dobrej komunikacji między zespołami pracującymi nad różnymi jej elementami.

Techniczne wyzwania

Jest kilka kwestii, o które musimy zadbać w systemach zbudowanych w oparciu o MSA. Są to:

Zarządzanie konfiguracją systemu

Jak sprytnie zarządzać konfiguracją kilkudziesięciu mikroserwisów, z których każdy może być uruchomiony w tym samym czasie w wielu instancjach?

Dynamiczne skalowanie

Jak wykorzystać naturalną zdolność mikroserwisów do skalowania i przeprowadzać tę operację automatycznie, w oparciu o aktualny ruch w systemie?

Logowanie i śledzenie ruchu użytkowników

Skoro każde żądanie może przejść przez dziesiątki różnych mikroserwisów przed powrotem do klienta, to jak możemy prześledzić jego ruch?

Obsługa błędów

Jak wykrywać i izolować uszkodzone mikroserwisy?

Gdzie w tym wszystkim jest Spring Cloud?

Spring Cloud to projekt, który zrzesza pod wspólną nazwą dziesiątki różnych bibliotek i frameworków stworzonych w celu zaadresowania wyżej wymienionych problemów.

Spring Cloud Config to serwer, który pomaga zarządzać konfiguracją mikroserwisów. Ribbon jest load-balancerem działającym w oparciu o dane otrzymywane od serwera Eureka (dane o mikroserwisach i ich instancjach). Hystrix dostarcza narzędzi służących do obsługi awarii, a Zipkin śledzi drogi przebyte przez nadchodzące do systemu żądania. W przypadku komunikacji opartej o protokół HTTP do grona zależności dołącza Feign, który znacząco upraszcza proces odpytywania zdalnych zasobów. Bramą do systemu bardzo często jest Zuul – serwer pracujący w charakterze APIGateway, czyli fasady, pod którą kryją się wywołania konkretnych mikroserwisów.

Projektów jest oczywiście więcej. Wymienione powyżej stanowią swoistego rodzaju fundament projektu Spring Cloud.