Architektura Mikroserwisów

Dobry, zły i brzydki

Start!!!

Robert Firek

@RobertFirek

Zawsze chciałem zostać architektem, a zostałem rzemieślnikiem ;) Jeśli ktoś chce pojść w moje ślady to zatrudniamy. Po szczegóły zapraszam po prezentacji.

[Mala sprawa organizacyjna. Jesli ktos ma jakies pytanie podczas prezentacji to prosze mi przerwac i od razu pytac. Jak odpowiedz bedzie za dluga lub skomplikowana to przesuniemy odpowiedz na przerwe]

brzydkiego.

Oto Monolit. Ten obraz mam przed oczami kiedy czlowiek opowiada o swojej aplikacji jako aplikacji monolitycznej.

Ciemna masa kodu, ktora jawi sie na zewnatrz jaka ciemna masa biznesowych opcji. Straszna niepoznana przestrzen.

Co dziwne takie podejscie jest nadal popularne i nie ma za miaru sie wycofywac. Wiekszosc z nas nadal pewnie pracuje w takim modelu i jakos wszyscy zyjemy. I malo tego sa to projekty, ktore odnosza sukcesy, a ludzie sa szczesliwi, ze moga w nich pracowac.

Dlaczego powstala wiec alternatywa w stosunku do takiej architektury.

Zanim odpowiemy na to pytanie przyjrzyjmy sie najpierw czym tak naprawde jest ten MONOLIT.

Jesli spojrzec glebiej w monolit to okazuje sie ze taki monolityczne to juz on nie jest.

W koncu nasza aplikacja musi eksponowac jakos swoje mozliwosci swiatu i wewnetrznie tez musi miec jakis wewnetrzny model.

I nie musi to byc swiat monolityczny. Kazdy element w ukladance naszej aplikacji jest elementem z innego swiata.

Mamy wiec baze danych od okreslonego dostawcy, ktora ma sie nijak do jezyka programowania, ktory uzywamy w naszej logice biznesowej.

Nasze aplikacje ma eksponuje swoje API czy GUI niekoniecznie w tym samym jezyku co logika biznesowa.

Oczywiscie takie zroznicowanie jest niezwykle rzadkie i w wiekszosci wypadkow technologie sa do siebie dostosowane.

Malo tego ...

... wewnetrznie kazdy element moze byc perfekcyjnie zoorganizowanym organizmem.

Kazdy modul ma wyodrebnione wlasne zadanie i wspolpracuja razem w celu osiagniacie wspolnego celu.

W koncu Uncle Bob nie napisal ksiazki na darmo i wszyscy produkujemy tylko czysty kod.

Gdzie lezy wiec problem.

Gdzie pewnie w kamieniu jest wypisane, ze na poczatku byl monolit.

Na poczatku twoja zespol liczy pewnie 5, gora 10 osob. Ustalenie jakiejkolwiek sprawy zajmuje 5 minut, bo kolega siedzi obok na krzesle. Rzucasz haslo, problem rozwiazany.

Jesli twoja firma odniesie sukces wielce prawdopodne jest to, ze twoj zespol sie powiekszy.

Nieunikniony stanie sie podzial na mniejsze zespoly i mamy taka sytuacje...

... kazdy zespol musi dokonac zmiany w tym samym module zeby rozwiac zupelnie inne rozwiazanie.

Kazdy walczy o dostep do tego samego moduly, zmiany zachodza na siebie. Teraz musimy ustalac kolejnosc, kto i na jakich zasadach ma dostep do kodu.

Wszelki decyzje wymagaja koordynacji miedzy zespolami, a czas od wprowadzenia

Trzeba tez ustalic kto i w jaki sposob...

..wrzuca zmiany na produkcje. I wreszcie kto jest odpowiedzialny jak cos pojdzie nie tak.

Ktora zmiana zepsula testy jednostkowe, a ktora zmiana zmienila wyniki testow integracyjnych.

Monolit nie ulatwia zycia duzym zespolom. Ktos ma takie doswiadczenia? :)

W monolitycznej aplikacji trzeba tez uwazac jaki wplyw na dzialanie innych modulow bedzie miala kazda zmiana.

Jako programisci lubimy tworzyc wielkie generyczne biblioteki, ktore "ulatwiaja nam zycie". Przewaznie laduje to w module UTILS. Kto nie popelnil tego grzechu niech podniesie reke

Problem w monolitycznej generycznej biblioteki lezy w jej uniwersalnosci. Jesli jest ona generyczna to musi wykonywac rozne zadania w roznym kontekscie.

Jak zobacze kod, ktory produkuje dane, z ktorych nie korzystam to powinienem je usunac. ALEEEE.... Ten sam kod jest uzywany przez zespol z drugiego konca biura albo swiata i musze pozostawic ten nic nie znaczacy kod dla innych.

Usuwanie duplikacji nie zawsze przynosi zamierzone korzysci.

To jest wlasnie powod dlaczego tak trudno jest pisac biblioteki ogolnego zastosowania.

Inny problem. Jak juz mowile to raczej rzadki przypadek kiedy aplikacja w architekturze monolityczne nie jest monolityczna na poziomie technologicznym.

Jako ze technologia uzyta w projekcie jest juz sprawdzona zespoly stosuja ja bezwiednie aby uniknac ewentualnych problem przy wdrozeniu.

Jesli uzywam mlotka wszystko wyglada jak gwozdzie. Takie podejscie nie pozwala na zastosowanie technologi odpowiednie do klasy problemu. Java przykladowo nie jest dobry rozwiazaniem jesli chodzi o BigData. Apache Spark z kolei nie jest dobrym rozwiazaniem do pisania aplikacji typu CRUD.

Powiazanie technologiczne z kolei czesto prowadzi do nastepnego problemu. Jesli przykladowo nasza aplikacja jest aplikacja internetowa i wybor nasz padl na Jave to wszystko mamy upakowane jako piekny, ogromny WAR.

Aplikacja zawiera wszystkie potrzebne moduly i kazdorazowo wymaga wrzucenia wszystkich elementow.

Teraz wyobrazmy sobie, ze obciazenie naszej aplikacji ze strony nasze strony www wzrasta. Aby zapobiec problemom dostawiamy sobie nastepny serwer i wrzucamy nasza aplikacje.

Dziala?!! Dziala.

Moment, moment. Nasza aplikacja jest obciazana jedynie po stronie internetowej. Nasze API nie wymaga skalowania. Zmarnowalismy wlasnie kawal zasobow w naszej chmurze i placimy za element, ktory nie jest kompletnie potrzebny.

Ok. Jest przeciez alternatywa mozemy na tej samej maszynie postawic jeszcze raz ten sam monolit. W ten sposob nie zmarnujemy cennego miejsca na naszej maszynie.

Tylko, ze w tym momencie wrzucilismy programistow na problemy z konfiguracja. Chcialbym odzyskac wszystkie godziny spedzone na konfigurowaniu aplikacji dla roznych srodowisk. Pewnie uzbieraloby sie tego na porzadne wakacje.

Tym razem takze marnujemy nasze cenne zasoby tylko, ze w inny sposob. Teraz marnujemy je na jednej maszynie nie uzywajac naszego API w niewielkim stopniu.

I tutaj do gry wchodzi...

Dobry.

Gdyby tak podzielic nasz monolit na male kawalki, gdzie kazdy z elementow bedzie odpowiedzialny za inny wycinek logiki biznesowej.

Oto podstawa architektury mikroserwisow. Dziel i rzadz. Nasza aplikacja jest teraz zespolem serwisow, ktory tworzy jedna aplikacje.

Jesli stwierdzimy ze mamy zamiar zmienic modul odpowiedzialny za API nie musimy juz nikogo pytac. Wprowadzamy nowa technologie, usuwamy nadmiarowy kod niezaleznie od innych serwisow.

I tutaj warto wspomniec o jednej z najwiekszych zalet tego typu architektury.

Kazdy serwis moze byc kompletnie niezalezny technologicznie. Jesli zespol preferuje Java nic nie stoi na przeszkodzie aby zaimplementowac serwis w Javie. To wlasny wybor tego zespolu:)

Niezaleznosc technologiczna rozciaga sie tez na bazy danych. Nie musimy juz wspoldzielic danych z innymi. Mikroserwis jest odpowiedzialny za logike, a wiec w konsekwencji tez za dane, ktorymi zarzadza.

Niezaleznosc technologiczna pozwala nam na jeszcze jedna rzecz. Zmiane organizacji zespolow.

Jesli mamy niezalezne serwisy to mozemy wokol nich zoorganizowac niezalezne zespoly. Pozwala sie to skupic na konretnym problemie, ktory dany serwis rozwiazuje.

Nieoczekiwana zaleta takiego rozwiazania jest mozliwosc przejscia do zespolu, ktory implementuje cos innego niz Encje JEE w Hibernacie. Jesli czujesz sie znudzony zmieniasz zespol nie prace.

Zeby w pelni wykorzystac ta zalete niezaleznosci trzeba wyksztalcic inna kulture pracy. Kulture pracy, w ktorej jestesmy odpowiedzialni nie tylko za swoj serwis, ale odpowiadamy za wszystkie razem. Nie tylko jako zespol, ale jako cala firma. Tylko wtedy zmiany w zespolach beda traktowane jak czesc procesu doskonalenia aplikacji.

Niezalezny zespol plus niezalezny serwis oznacza niezalezny deployment.

Teraz zespol decyduje kiedy i jak dany serwis trafia na produkcje. Caly przeplyw od wrzucenia kodu do pojewienia sie na produkcji jest w pelni pod kontrola tylko jednego zespolu.

Jesli masz krytycznego bug'a nie boisz sie go wrzucic. Nie czekasz w nieskonczonosc na inne zespoly. Ty jestes u steru.

Dobrze. Aplikacja podzielona i wrzucona na produkcje ale teraz musimy odpowiedziec sobie jak te serwisy komunikuja sie.

Teraz czesci skladowe aplikacji nie egzystuja w jednym miejscu. Niezaleznosc technologiczna wymusza nowe sposoby komunikacji na kazdym z serwisow.

Aby zrozumiec sie nawzajem konieczny jest sposob, ktory bedzie zrozumialy dla obydwu stron. Jaki wiec protokol trzeba zastosowac zeby byl zrozumialy dla kazdego jezyka. Oczywiscie HTTP. Protokol HTTP jest protokolem podstawowym dla prawie kazdego jezyka. Jesli jego nadinterpretacja prawie niemozliwa stal sie on naturalnym kandydatem.

Z tego samego powodu popularnosc zdobyl JSON jako formatu danych. Poprzez protokol HTTP slemy JSON/XML. Kazdy jest w stanie bez przeszkod skomunikowac sie i zinterpretowac przekazane dane.

Ok. Sprawa komunikacji zalatwiona. Teraz mozemy ukladac nasze serwisy jak puzzle.

Skalowanie nie jest problemem. Kazdy serwis jest na tyle maly, ze skalujemy znowu NIEZALEZNIE od innych.

Jesli teraz konieczne jest obsluzenie wiekszej ilosci zgloszen w jednej czesci systemu, skalujemy tylko ta czesc.

Jako ze jestesmy mniejsi mozemy uruchomic sie wielokrotnie na jednej maszynie. Teraz wykorzystanie naszych zasobow jest bardziej optymalne.

Ktos pewnie teraz powie "Zaraz, zaraz. Przeciez kazdy serwis ma jakis stan. W jaki sposob ten stan jest dzielony". Otoz mikroserwisy nie powinny posiadac stanu. Bezstanowosc nie oznacza, ze nie mamy danych. Mamy ale powinny byc one dostepne w bazie danych, ktora jest zrodlem. Nie jest to twardy wymog, ale powoduje mniej problemow.

Mamy aplikacje podzielona, rozrzucona po calej infrastrukturze, komunikujaca sie ze soba bez przeszkod. Tylko skad ja wiem czy to dziala i czy dziala dobrze.

Monitoring. Monitoring. I jeszcze raz monitoring.

Powtorze to co mowia osoby, ktore wdrazaja mikroserwisy:

"Jesli cos sie rusza zrob z tego wykres, graf". "Jesli cos sie nie rusza zrob z tego wykres, graf. Moze zrobilo sobie przerwe."

Nasza aplikacja jest teraz systemem rozproszonym z niejednolitymi technologiami. Bez wiedzy na temat CO i JAK sie porusza w systemie jestesmy slepi.

Co konkretnie wiec mamy monitorowac. Rzeczy podstawowe jak obciazenie procesora, ilosc dysku na maszynie, wszystko co dzieje sie na konkretnej maszynie,

stan serwisow, stan narzedzi wspierajacych , logi serwisow, ilosc danych wysylanych z/do sieci.

WSZYSTKO. DOSLOWNIE WSZYSTKO.

Samo zbieranie to nie wszystko. Dane zbieramy i aktywnie analizujemy. Po co analizujemy. Po to by miec Automatyczny System Wczesnego Ostrzegania o problemach zanim zabija nasz system.

Automatyczny System Wczesnego Ostrzegania daje nam jeszcze nieoceniona mozliwosc. Mozliwosc stworzenia systemu AUTOMATYCZNEGO NAPRAWIANIA problemu. Jesli monitorujemy tak wiele elementow i przygotujemy odpowiednie wizualizacje na 80% znajdziemy jakies wzory. Nasze mozgi sa do tego przygotowane od poczatku istnienia ludzkosci. Jesli mamy wzor problemu to mozemy wykonac pewne operacje bez ingerencji czlowieka.

Koniec z telefonami o 3ej nad ranem i wyrywanie czlowieka ze srodka urlopu. Po to dzielismy aplikacje, aby teraz nasza reakcja bylo ukierunkowana na odpowiedni cel. Nie na caly system.

Mysle ze z grubsza zdefiniowalismy glowne cechy architektury mikroserwisow. Czas na...

ZLEGO. Zadne rozwiaznie jest srebrna kula, ktora rozwiaze wszystkie twoje problemy. Co wiec poswiecilismy na oltarzu nowoczesnoci.

Testowalnosc. Pierwsza ofiara mikroserwisow. W przypadku monolitycznej aplikacji pokrycie kodu testami jednostkowymi dawalo na duza pewnosc, ze aplikacja bedzie dzialac poprawnie.

Nadal to jest prawda ale dziala to niestety tylko w skali micro. Jesli serwisy byly wczesniej modulami jak teraz mam testowac wspoldzialanie miedzy modulami.

Musimy stworzyc dodatkowy twor pozwalajacy nam na harmonijna wspoprace miedzy serwisami.

Tym tworem jest kontrakt. Umowa potwierdzajaca sposob komunikacji miedzy serwisami. Kazda zmiana w danych wyjsciowych powinna zostac umieszczona i przetestowana wzgledem kontraktu.

Zmiany w kontrakcie nie mozna sobie dodac "O! Tak!". Konieczna jest akceptacja umowy ze strony konsumentow. Stad nazwa Consumer Driven Contract - Kontrakt prowadzony przez konsumenta.

Cala niezaleznosc poszla do kosza. Teraz nie moge zlamac testow kontraktowych, a jesli bede chcial zlamac sposob komunikacji to bede musial sie zmierzyc z silami innych serwisow - zespolem odpowiedzialnym za konsumpcje moich danych.

Tutaj wraca stary temat kultury pracy. W tym miejscu szczegolnie wazne jest poczucie wspoldzialania w ramach produktu, jakim jest cala aplikacja, a nie myslenia tylko o swoim serwisie. Konflikty sa nieuniknione, ale wazne jest jak je rozwiazujemy, a nie jak ich unikamy.

Ktos pewnie podpowie wam, ze mozna wprowadzic testy calego systemu. Uruchomimy sobie srodowisko testowe, staging czy cos podobnego i tam w warunkach zblizonych do produkcyjnych potestujemy cala aplikacje.

Unikajcie tych testow jak ognia. Cale zlo w firmach lezy w testach E2E. 2 lata temu mialem okazje ugrzeznac w takich testach. Koszmary mam do dzisiaj.

Dlaczego zalecam to unikac:

  1. Jak bardzo twoje srodowisko jest podobne do produkcyjnego. Czy mozesz polegac na tej konfiguracji?
  2. Ile to bedzie kosztowac? To juz problem twojego manager.

3. Kto jest winny kiedy test pojdzie nie tak. Przy odrobinie szczescia mamy dobry monitoring i mozemy przesledzic sciezke problemu. Tylko ile czasu nam to zajmie zeby to ustalic.

  1. Jak zmierzyc pokrycie? Czy jest jakis element w systemie, ktory moze polozyc cala aplikacje?

Nie mowie, ze takich testow nie nalezy pisac. Zeby tylko nikomu nie wydawalo sie ze wielkosc trapezu na slajdzie oznacza ilosc testow.

Piramidka testow musi byc zachowana. Jak najwiecej jednostkowych testow. Troche mniej kontrakto-integracyjnych. W koncu jak najmniej E2E. Zostawiamy sobie jeszcze miejsce na losowe klikanie po aplikacji.

Co jeszcze moze pojsc nie tak?

Rozproszonosc systemu moze byc zaleta i wada.

Zeby zobrazowac problemy posilimy sie czyjas madroscia. Kilku ludzi w Sun Microsystems na podstawie eksperymentow wyodebrnili 8 mitow dotyczacych systemow rozproszonych. Trzy z nich dotykaja mikroserwisy szczegolnie. Sa to:

  1. The network is reliable. Siec jest niezawodna
  2. Latency is zero. Opoznienie jest zerowe.
  3. Bandwidth is infinite. Przepustowosc jest niegraniczona.

Te trzy wybrane mity mowia nam jak duzo rzeczy zakladamy piszac nasz kod i jak bardzo sie mylimy. Dlatego niezwykle istotne jest aby nasze serwisy byly odporne na tego typu problemy.

Jesli siec przestanie dzialac lub odpowiedzi z innego serwisu nie bede naplywaly w odpowiednim tempie, musimy przewidziec taka sytuacje i byc gotowi dzialac dalaja ale w stanie wyjatkowym.

Musimy byc tez gotowi na powrot do stanu normalnego. Wyrzucenie RuntimeException nie wchodzi juz w gre. Usmiercanie serwisu przy byle okazji nie jest naszym celem.

Wszelkie stany wyjatkowe pojawiajace sie w serwisie powinny byc monitorowane. Monitorowanie daje nam mozliwosc sprawdzenia glownej przyczyny i reakcje zanim problem zabije wszystkie nasze serwisy.

Niezaleznosc technologiczna tez moze okazac sie przeklenstwem.

Wyobrazmy sobie sytacje, gdy kazdy z serwisow musi rozwiazac identyczny problem, czy to technologiczny, czy biznesowy. W monolitycznej aplikacji rozwiazaniem byloby stworznie odzielnego modulu, ktory bedzie odpowiadal za rozwiazanie tego problemu.

Kazdy z serwisow musi rozwiazac ten problem w obrebie swojego wlasnego stosu technologicznego. Dzielenie sie biblioteka napisana w Ruby z Java jest pewnie ekstremalnie trudne i rownie ekstremalnie glupie.

W praktycy jesli mamy problem do rozwiazania, ktory dotyka prawie wszystkich serwisow, z automatu problem przeksztalca sie w nowy kontekst dzialania naszej aplikacji. Wymaga on modelowania, a co za tym idzie nowego serwisu.

Problem nie zawsze jest jedna wystarczajaco duzy, zeby pojsc ta sciezka. Jesli bedziemy tworzyc zbyt duzo serwisow, istnieje ryzyko zabicia systemu poprzez pikowanie. Pikoserwis tam, pikoserwis tutaj, pikoserwisy wszedzie. Pikoserwisy doprowadza cie do szalenstwa swoim niewielkim rozmiarem i zlozonoscia srodowiska, w ktorym przyjdzie im zyc.

Wystarczy tej wycieczki po czubku gory lodowej.

Mikroserwisy

Czym wiec sa wiec Microserwisy?

Czy jest to Metodyka? W pewnym sensie jest to jakaś standaryzacja podejścia do problemu.

Czy jest to Architektura? W pewnym sensie jest to sposób na organizacje oprogramowania.

Wszyscy szukamy ścisłej definicji i jest o nia niezwykle trudno. Zapewnie wiele firm będzie was przekonywać, że to jest Spring Boot albo jakis inne oprogramowanie. Nie sluchajcie ich.

Niektorzy beda was przekonywac, ze zmiana na Mikroserwisy naprawi wasze problem biznesowe i technologiczne. Nie sluchajcie ich.

vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

Mikroserwisy to sposob myslenia o aplikacji w sposob calosciowy poczawszy od sposobu organizacji kodu poprzez infrastrukture po organizacje twojego zespolu.

Dziekuje. Mama nadzieje ze nie zanudzilem na smierc. Pytania ?

???

Pytania

SpaceForward
Right, Down, Page DownNext slide
Left, Up, Page UpPrevious slide
POpen presenter console
HToggle this help