W świecie mikroserwisów pojawia się temat sposobu ich integracji, aby wymienić wiedzę i udostępnić usługi pomiędzy domenami. Dwa popularne podejścia to komunikacja synchroniczna (np. HTTP, REST) oraz integracja przez system kolejkowy typu Apache Kafka, RabbitMQ czy JMS (Java Message Service np. Tibco).
Każde podejście ma szereg wad i zalet, dlatego przed podjęciem decyzji należy zrozumieć przypadek użycia, poznać kontekst biznesowy i wymagania niefunkcjonalne oraz przeprowadzić analizę za i przeciw cechom każdego z rozwiązań.
W tym artykule dowiesz się:
- Jak działa integracja synchroniczna HTTP/REST
- Jak działa integracja przy użyciu systemów kolejkowych
- Jakie heurystyki pomogą Ci podjąć decyzję, który sposób integracji wybrać, np.:
- Sposób komunikacji (orkiestracja vs choreografia)
- Szybki dostęp do informacji
- Asynchroniczne przetwarzanie
- Dostępność aplikacji
- Pewność wykonania operacji
HTTP/REST, komunikacja synchroniczna
Komunikacja za pomocą HTTP/REST należy do kategorii komunikacji synchronicznej. Oznacza to, że komponent inicjujący komunikację (Klient) wysyła żądanie, a następnie utrzymuje połączenie, czekając na odpowiedź zdalnej usługi (Serwera). Jest to stosunkowo prosty schemat komunikacji. Obie strony komunikacji muszą być dostępne w tym samym czasie, kiedy zachodzi wywołanie żądania. Serwer powinien odpowiedzieć Klientowi na żądanie w akceptowalnym czasie. Oznacza to, że wynik dla żądania również musi być dostępny w akceptowalnym czasie.
Gdy wystąpi błąd obsługi żądania, połączenie jest zrywane, a operacja nie powiedzie się. Podobnie w sytuacji, gdy wystąpi timeout, czyli osiągnięcie maksymalnego czasu odpowiedzi.
Komunikacja synchroniczna doskonale spisuje się dla operacji odczytu (typu read). Gdy potrzebna jest informacja na temat stanu w systemie w konkretnym czasie, otrzymujemy odpowiedź w danej chwili.
Jeżeli żądanie jest operacją sygnalizującą istotną zmianę w systemie (operacja typu write) i występuje błąd, to po stronie Klienta inicjującego komunikację spoczywa odpowiedzialność obsługi błędnej sytuacji.
- Można ją ponawiać w razie krótkotrwałych awarii stosując Retry Pattern (czytaj więcej).
- W przypadku długotrwałych awarii można z góry przerwać złożenie żądania stosując Circuit Breaker Pattern (czytaj więcej).
- Jeżeli błąd pozostaje, należy albo poinformować użytkownika o nieudanej operacji, albo zaimplementować mechanizm dłuższego ponawiania procesu. Komplikuje to nieco kod Klienta.
Klient musi znać konkretny adres usługi Serwera, do której się łączy: adres instancji aplikacji. Jeżeli Serwer jest wdrożony jako wiele instancji aplikacji, zazwyczaj Klient korzysta z usługi proxy – Load Balancer’a – który przekazuje żądania do konkretnych instancji usług.
Komunikacja przez Systemy Kolejkowe
Architektury zintegrowane przez Systemy Kolejkowe zakładają aplikacje komunikujące się poprzez wymianę komunikatów (Messages). Z jednej strony są Producenci wiadomości (Producers), a drugiej Konsumenci (Consumers). Wiadomości wysyłane są na szynę danych (zwaną Message Broker / Message Bus).
Producenci nie znają bezpośrednio Konsumentów, komunikują się tylko z szyną danych. Producenci i Konsumenci nie muszą być dostępni w czasie zlecania i przetwarzania operacji. Wiadomości są gromadzone na szynie danych i buforowane.
Integracja tego typu nie gwarantuje wykonania operacji, a jedynie przekazanie wiadomości. Producent może otrzymać jedynie potwierdzenie przyjęcia (ACK – acknowledge) wiadomości przez szynę danych. Konsument może odesłać potwierdzenie przyjęcia wiadomości (ACK – acknowledge – w momencie konsumowania lub po poprawnym przetworzeniu) lub odrzucić wiadomość (NACK – not acknowledged – w przypadku błędu przetwarzania).
Jeżeli Producent jest zainteresowany otrzymaniem statusu wykonania operacji przez Konsumenta, ten musi wysłać wiadomość zwrotną.
Zaletą rozwiązania jest asynchroniczne przetwarzanie – Konsument może wykonywać operacje w swoim tempie, nie obciążając Producenta. Nieprzetworzone wiadomości wciąż pozostają na szynie danych. Jeżeli wiadomość musi być przetworzona w danym czasie, istnieje możliwość ustawienia tzw. TTL (time-to-live), czyli okresu przydatności wiadomości.
Potencjalną wadą może być to, że awaria szyny danych może doprowadzić do uszkodzenia całej architektury. Nie jest to do końca dyskwalifikująca obiekcja – istnieją wysoko dostępne szyny danych takie jak Apache Kafka, czy Tibco EMS.
Jakiego typu integrację wybrać?
Podjęcie decyzji powinno być przemyślane w danym kontekście użycia. Poniżej skupię się na paru heurystykach, które pomogą Ci podjąć decyzję lub będą zaczątkiem do dyskusji na ten temat w zespole.
1. Sposób komunikacji (orkiestracja vs choreografia)
Zastanów się, jakiego typu komunikacja będzie potrzebna:
- jeden-do-jeden
- jeden-do-wielu (rozgłaszanie komunikatu)
Dla prostych integracji można rozważyć zarówno komunikację synchroniczną, jak i przez systemy kolejkowe uwzględniając to, co możesz zrobić w przypadku błędu obsługi żądania oraz tego czy wyniku operacji potrzebujesz natychmiast, czy może to być informacja zwrotna „za jakiś czas”.
W systemie mogą następować pewne rozgłaszane zdarzenia biznesowe. Wtedy masz do czynienia z komunikacją jeden-do-wielu. Przykład: należy poinformować kilka systemów o przyjęciu zamówienia od klienta:
- System obsługujący dostawy, aby zlecić zaplanowanie dostawę.
- System stanu magazynowego, aby zarezerwować ilości magazynowe.
- System obsługujący punkty lojalnościowe, aby naliczyć punkty za zamówienie.
W takim przypadku zamiast wywołując wszystkie serwisy po kolei (oraz obsługiwać cały proces za pomocą sagi w przypadku pojedynczych błędów, co komplikuje nieco system) możesz zastosować komunikację przez szynę danych i rozgłosić wiadomość o zaistniałym zdarzeniu.
Istnieje zasadnicza różnica pomiędzy imperatywnym instruowaniem co i kto ma zrobić od zgłoszenia zdarzenia i pozwolenia systemowi samemu na nie zareagować.
Pierwsze podejście to orkiestracja. Przypomina dyrygenta, który wskazuje, kiedy ma zagrać orkiestra. Z podejściem masz do czynienia, gdy wywołujesz poszczególne serwisy w procesie, zlecając operacje po kolei.
Innym jest choreografia, kiedy na dane zdarzenie system sam odpowiada reakcją. Możesz wyobrazić sobie zespół tancerzy, w którym lider rozpoczyna jakiś ruch, a reszta tancerzy, bacznie obserwując lidera, kontynuuje figury. Akcja-reakcja w kompozycji tworzy pełną harmonię (bez dyrygenta!).
2. Szybki dostęp do informacji
Jeżeli potrzebujesz bardzo szybkiego dostępu do informacji (odczyt), zdecydowanie skorzystaj z integracji synchronicznej. Musisz jednak zapewnić bardzo szybki dostęp do danych (np. przechowywane w pamięci lub bazie danych).
Przykłady:
- Status przesyłki, zwracany bezpośrednio z bazy danych
- Status obróbki pliku video, zwracany bezpośrednio z bazy danych, ale przetwarzanie następuje już asynchronicznie. Operacja odczytuje tylko status w bazie danych. Asynchroniczne przetworzenie zmienia status.
Antywzorce:
- Pytanie o status operacji przez system kolejkowy. W przypadku zwolnienia działania Konsumenta, żądania zlecone Producentowi i tak są zawieszone, a Konsument po czasie może odpowiadać na wiadomości, na które już nikt nie czeka.
3. Asynchroniczne przetwarzanie
Do systemu zlecane są pewne operacje. Jeżeli spójność systemu na to pozwala, mogą być przetworzone od razu, a zmiany zapisane – wtedy wybierz prostą komunikację synchroniczną.
Jeżeli natomiast wykonanie operacji wymaga długiego przetwarzania, warto wysłać taką operację na system kolejkowy. Konsument przetworzy ją w swoim czasie i odeśle odpowiedź. Jednocześnie nieprzetworzone operacje będą oczekiwały na szynie danych.
W przypadku podejścia synchronicznej integracji, dla długo trwających operacji musisz zlecić jej wykonanie, a następnie periodycznie (co jakiś czas) odpytywać się o status wykonania. Wymaga to po stornie Klienta implementacji mechanizmu odpytywania. Po stronie Konsumenta wymagane jest zapisania zadania, przetwarzania zadań zapisanych w kolejce i implementację mechnizmu zwracania statusu odpowiedzi. W protokole HTTP zwykle przyjęcie zadania zwraca status 202 Accepted, a następnie Klient odpytuje się o status wykonania.
Rozważ uproszczenie integracji swoich aplikacji po prostu przez system kolejkowy, jeżeli to możliwe, a oszczędzisz pracy na implementowanie podobnego mechanizmu w aplikacji.
4. Dostępność aplikacji
Z pewnych względów może być tak, że zintegrowany system może być niedostępny w momencie zlecania operacji lub z jakiegoś powodu nie może jej teraz wykonać. A operacja musi być zrobiona, prędzej czy później.
W przypadku użycia systemów kolejkowych istnieje możliwość wysłania wiadomości na szynę danych, na której zostanie ona zbuforowana, a Konsument w odpowiednim czasie podejmie operację.
Oznacza to, że Producent i Konsument nie muszą być obaj dostępni w momencie przetwarzania operacji, co jest niemożliwe w przypadku komunikacji synchronicznej. W przypadku niedostępności Serwera w komunikacji synchronicznej operacja nie powiedzie się, a zastosowanie mają Retry Pattern i Circuit Breaker Pattern.
5. Pewność wykonania operacji
Systemy kolejkowe dają możliwość otrzymania:
- Gwarancji opublikowania wiadomości na szynie danych – wtedy możemy wysłać potwierdzenie do klienta o przyjęciu operacji do realizacji (jeszcze nie wyniku tej operacji).
- Potwierdzenia przyjęcia wiadomości przez Konsumenta – decyduje on, kiedy potwierdza przyjęcie, czy na początku przetwarzania, czy na końcu. Jeżeli na końcu przetwarzania to mamy pewność, że przed wykasowaniem wiadomości z szyny danych, operacja została przetworzona. Jeżeli podczas przetwarzania wystąpił błąd, wiadomość trafia z powrotem na szynę.
Daje to pewność, że komunikacja nie jest przerwana i zagubiona, co mogłoby wystąpić podczas przetwarzania synchronicznego – stracone połączenie, podczas gdy Serwer kończy pracę nad przetwarzaniem operacji.
Podsumowanie
Wybór metody integracji aplikacji nie powinien być przypadkowy. Przed podjęciem decyzji rozważ wszystkie za i przeciw komunikacji synchronicznej po HTTP/REST oraz systemem kolejkowym. Mam nadzieję, że zaprezentowane heurystyki Ci w tym pomogą.
Wpis który czytasz to zaledwie fragment wiedzy zawartej w Programie szkoleniowym Java Developera od SoftwareSkill. Mamy do przekazania sporo usystematyzowanej wiedzy z zakresu kluczowych kompetencji i umiejętności Java Developera. Program składa się z kilku modułów w cotygodniowych dawkach wiedzy w formie video.
Gdybyś potrzebował jeszcze więcej:
Jesteś Java Developerem?
Przejdź na wyższy poziom wiedzy
„Droga do Seniora” 🔥💪
Jesteś Team Leaderem? Masz zespół?
Podnieś efektywność i wiedzę swojego zespołu 👌