W poprzednim rozdziale przygotowaliśmy usługę rejestrującą Eureki, a także stworzyliśmy mikroserwis,
którego dwie instancje zostały dodane do rejestru. Teraz zajmiemy się budową web clienta zainteresowanego
wywołaniem usługi mikroserwisu. Przeanalizujmy, co dokładnie ma się wydarzyć.
Aplikacja kliencka (web client, client) ma do wykonania pewne zadanie. Logika tego zadania jest zamknięta
wewnątrz kodu naszego mikroserwisu. Aplikacja kliencka oczekuje wykonania logiki, a to, jak i gdzie i przez
jaką instancję logika ta będzie wykonana, nie ma dla niej żadnego znaczenia.
Innymi słowy, klient wyśle żądanie pod adres usługi, a to która instancja mikroserwisu faktycznie wykona obsługę żądania,
pozostanie już w gestii Eureki. Klient nie będzie miał wpływu na to, która instancja zostanie wybrana.
Nie będzie też nic wiedział o faktycznej lokalizacji mikroserwisu.
Idea stosowania mikroserwisow wiąże się również ze skalowaniem systemu, czyli zwiększaniem ilości instancji mikroserwisu
wykonujących daną pracę. W dalszej części rozdziału pokażemy, jak wygląda to z bliska. Uruchomimy dwie instancje mikroserwisu, które
będą na zmianę wykonywały to samo zadanie. Najpierw jednak zacznijmy od stworzenia projektu klienta.
Projekt eureka.web.client
Tworzymy projekt aplikacji klienckiej. W tym celu wchodzimy na stronę
Spring initializera i tworzymy
projekt jak na poniższym zdjęciu. Poza metadanymi projektu i wersją Spring Boot-a niezwykle ważne jest dodanie
zaznaczonych zależności (dependencies).
Po skonfigurowaniu pobieramy projekt
(Generate) i
rozpakowujemy go na dysku.
Appa Notka.
Dodajmy, że Thymeleaf nie jest wymagany do samego zorganizowania architektury mikroserwisów, ale przyda się nam, aby
pokazać działanie klienta. Wykonamy w nim mały fragment widoku wyświetlającego w przeglądarce informacje otrzymane
z mikroserwisu. Natomiast Spring Web jest nam potrzebny do tego, aby uzyskać dostęp do klasy RestTemplate, za pomocą której
wyślemy request z naszego klienta do Eureki.
Dalej importujemy projekt jako
Maven project do naszego IDE. Efekt importu jest taki jak poniżej.
W celu zwiększenia czytelności zmieniliśmy nazwę wygenerowanej klasy z
Application na
EurekaWebApp.
Dostarczamy konfigurację polegającą na zdefiniowaniu portu, pod którym nasz klient będzie dostępny.
Konfigurację dodajemy do pliku
application.properties (
/src/main/resources/application.properties):
Kontroler webowy
W naszej mini aplikacji dodajemy kontroler, który przyjmie żądanie
GET i uruchomi metodę
process.
Metoda wykorzystuje obiekt klasy
RestTemplate, którego zadaniem jest wykonanie
wysłania requestu na konkretny
URL. W ten sposób kontroler skontaktuje się z rejestrem Eureki, a więc z pośrednikiem,
a on wybierze docelową instancję wykonującą zadanie.
Dodamy jeszcze drobny fragment frontendu, posiłkując się
Thymeleaf. Będziemy pokazywać w przeglądarce
msg
i
time. Najważniejsza jest zmienna
msg, ponieważ ona przechowuje zawartość
wiadomości zwróconej przez docelowy mikroserwis:
Odwołanie do tego mikroserwisu odbywa się za pomocą usługi pośredniczącej, więc potrzebujemy go jakoś zidentyfikować.
W tym celu używamy nazwy mikroserwisu (
eureka.microservice) wraz z nazwą mapowania
GET (
process).
Oczywiście takie mapowanie musi istnieć a nszym mikroserwisie.
Dlatego też dodajemy do kodu projektu
eureka.microservice z poprzedniego rozdziału poniższy kontroler z zadanym mapowaniem:
To tutaj konstruujemy wiadomość, która finalnie jest zwracana do klienta po wykonaniu metody
process.
Podsumujmy teraz kolejne kroki:
-
W projekcie eureka.web.client dodaliśmy metodę uruchamianą na wysłanie żądania GET
z przeglądarki.
-
Nasz mikroserwis eureka.web.client wywołał po nazwie mikroserwis i metodę, którą jest on zainteresowany (eureka.mikroservice/process).
-
Pośrednik (eureka.server) otrzymał żądanie z nazwą mikroserwisu, dzięki czemu wie, który serwis wywołać.
To jaką instancję uruchomi, zależy już od niego.
-
Pośrednik otrzymuje odpowiedź z mikroserwisu (eureka.microservice) i odsyła ją do klienta (eureka.web.client).
-
Odpowiedź jest wyświetlana w przeglądarce dzięki wykorzystaniu Thymeleaf.
RestTemplate i adnotacja @LoadBalanced
Wyżej napisaliśmy, że do uruchomienia usługi potrzebna jest klasa
RestTemplate
(ew. można też użyć innych rozwiązań np.
FeignClient), co oczywiście jest prawdą.
Problem w tym, że klasa ta nie jest domyślnie dostępna jako bean, więc musimy sobie takiego beana stworzyć.
Oprócz tego, że tworzymy beana
restTemplate, to jeszcze do metody tworzącej dodajemy
adnotację
@LoadBalanced. Robimy tak, ponieważ chcemy poinformować naszą Eurekę,
aby wykonywała "balansowanie obciążeniem", czyli aby wykorzystywała różne instancje mikroserwisu do obsłużenia żądania.
Owo balansowanie obciążeniem domyślnie jest wykonywane za pomocą algorytmu
round-robin,
a więc wykorzystywane są po kolei wszystkie opcje, a w momencie ich wyczerpania algorytm startuje od początku.
Tłumacząc to na język usług, każde kolejne żądanie będzie obsługiwane przez instancję, która jeszcze tego nie robiła,
a jak już wszystkie instancje wykonają zadanie przynajmniej raz, wówczas proces jest powtarzany.
W ten sposób obciążenie jest rozkładane równomiernie miedzy wszystkie instancje.
W przypadku gdy mamy dwa mikroserwisy, będą one obsługiwały żądanie na zmianę, co doskonale widać, gdy
uruchomimy kolejno: projekt
eureka.server, dwie instancje
eureka.microservice oraz instancję naszego klienta
eureka.web.client:
i wtedy zaczniemy wysyłać żądania jedno po drugim:
Widać wyraźnie, że wiadomości są zwracane z dwóch różnych instancji i na każdej z nich inkrementacja jest wykonywana niezależnie.
Autor: Kasia Kowolik
Data: 25 października 2020
Labele:Backend, Poziom średniozaawansowany, Java, Mikroserwisy, Spring, Spring Boot
Linki:
Spring Boot Initializr
https://github.com/javappa-coding/eureka-service-discovery