Mikroserwisy w akcji. Отсутствует
i niekrytyczne
Wraz z rozwojem systemu niektóre funkcjonalności w sposób naturalny staną się bardziej krytyczne dla potrzeb naszych klientów i skutecznego działania firmy niż inne. Na przykład w SimpleBanku usługa obsługi zleceń znajduje się na ścieżce krytycznej dla złożenia zlecenia. Bez tej działającej poprawnie usługi nie można wykonywać zleceń klientów. I odwrotnie, inne usługi są mniej istotne; jeśli usługa profilu klienta jest niedostępna, jest mniej prawdopodobne, że wpłynie ona na krytyczny, generujący przychody element naszej oferty. Na rysunku 3.9 zilustrowano przykładowe ścieżki w SimpleBanku.
Rysunek 3.9. Łańcuchy usług tworzą zdolności. Wiele usług będzie znajdować się na wielu ścieżkach
To miecz obosieczny. Im więcej usług będzie na ścieżce krytycznej, tym bardziej prawdopodobna będzie awaria. Ponieważ żadna usługa nie jest w 100% niezawodna, skumulowana niezawodność usługi jest wynikiem niezawodności jej zależności.
Mikroserwisy pozwalają jednak wyraźnie zidentyfikować te ścieżki i traktować je niezależnie, pozwalając na zainwestowanie więcej wysiłku w maksymalizowanie odporności i skalowalności tych ścieżek zamiast w mniej istotne obszary systemu.
3.4. Komunikacja
Komunikacja jest podstawowym elementem aplikacji mikroserwisowej. Mikroserwisy komunikują się ze sobą, aby wykonać konkretne zadania. Kształt tworzonej aplikacji określają wybrane przez nas dla mikroserwisów sposoby wydawania poleceń i żądań wykonania działań w stosunku do innych mikroserwisów.
PORADA Komunikacja w sieci jest również głównym źródłem awaryjności w aplikacji mikroserwisowej. W rozdziale 6 omówimy techniki maksymalizacji niezawodności komunikacji między usługami.
Komunikacja nie jest niezależną warstwą architektoniczną, ale przenieśliśmy ją do osobnej części, ponieważ zaciera ona granicę między warstwami usług i platformy. Niektóre elementy, takie jak brokerzy komunikacji, są częścią warstwy platformy. Ale same usługi są odpowiedzialne za konstruowanie i wysyłanie komunikatów. Chcemy zbudować logikę w punktach końcowych przy prostocie kanałów (smart endpoints and dumb pipes).
W tym podrozdziale omówimy typowe wzorce komunikacji w mikroserwisach oraz ich wpływ na elastyczność i ewolucję aplikacji mikroserwisowej. Większość dojrzałych aplikacji mikroserwisowych łączy zarówno style interakcji synchronicznej, jak i asynchronicznej.
3.4.1. Kiedy używać komunikatów synchronicznych
Komunikaty synchroniczne są często pierwszym podejściem do projektowania, które przychodzi na myśl. Są dobrze dopasowane do scenariuszy, w których wyniki działania – albo potwierdzenie sukcesu, albo porażki – są wymagane przed przystąpieniem do kolejnego działania.
Na rysunku 3.10 pokazano wzorzec żądanie–odpowiedź dla komunikatów synchronicznych. Pierwsza usługa tworzy odpowiedni komunikat do współpracownika, który aplikacja wysyła za pomocą mechanizmu transportowego, takiego jak HTTP. Usługa docelowa odbiera ten komunikat i odpowiednio reaguje.
Rysunek 3.10. Synchroniczny cykl życia żądanie–odpowiedź między dwiema usługami komunikacyjnymi
WYBÓR KOMUNIKACJI
Wybór sposobu komunikacji – RESTful HTTP, biblioteki RPC lub czegoś innego – będzie miało wpływ na projektowanie naszych usług. Każdy sposób komunikacji ma inne właściwości związane z opóźnieniem, wsparciem języka i elastycznością. Na przykład gRPC zapewnia generowanie kontraktów API klienta/serwera za pomocą Protobufs, podczas gdy HTTP jest agnostyczny w zakresie kontekstu komunikatów. W całej aplikacji stosowanie jednej metody komunikacji synchronicznej zapewnia efekt skali; łatwiej jest to zrozumieć, monitorować i wspierać za pomocą narzędzi.
Ważna jest także separacja potrzeb między mikroserwisami. Wybrany przez nas mechanizm komunikacji powinien zostać odseparowany od logiki biznesowej usługi, która z kolei nie powinna wiedzieć o kodach statusu HTTP lub strumieniach odpowiedzi gRPC. W ten sposób łatwiej będzie wymieniać różne mechanizmy w przyszłości, jeśli potrzeby naszej aplikacji będą ewoluować.
WADY
Komunikacja synchroniczna ma ograniczenia:
■ tworzy ściślejsze powiązania między usługami, ponieważ muszą one być świadome usług z nimi współpracujących;
■ nie ma silnego modelu wspierającego wzorzec rozgłoszeniowy lub publish-subscribe, ograniczając naszą zdolność do wykonywania równoległych działań;
■ blokuje wykonywanie kodu podczas oczekiwania na odpowiedzi; w modelu serwera opartym na wątkach lub procesach może to spowodować zmniejszanie wydajności infrastruktury i wyzwalanie awarii kaskadowych;
■ nadużywanie komunikatów synchronicznych może tworzyć głębokie łańcuchy zależności, co zwiększa ogólną kruchość ścieżki wywołania.
3.4.2. Kiedy używać komunikatów asynchronicznych
Asynchroniczny styl przesyłania komunikatów jest bardziej elastyczny. Przez wprowadzenie zdarzeń można łatwo rozszerzyć system, aby sprostać nowym wymaganiom, ponieważ usługi nie muszą mieć wiedzy o ich klientach niższego szczebla. Nowe usługi mogą wykorzystywać istniejące zdarzenia bez zmiany istniejących usług.
WSKAZÓWKA Zdarzenia reprezentują zmiany stanu po fakcie. OrderCreated, OrderPlaced i OrderCanceled są przykładami zdarzeń, które może generować usługa obsługi zleceń SimpleBanku.
Ten styl umożliwia bardziej płynną ewolucję i tworzy luźniejsze powiązania między usługami. Kosztem tego jest jednak to, że asynchroniczne interakcje są trudniejsze do analizowania, ponieważ ogólne zachowanie systemu nie jest już jawnie zakodowane w liniowej sekwencji. Zachowanie systemu będzie coraz bardziej wynikające – w nieprzewidziany sposób z interakcji między usługami – wymagając inwestycji w monitorowanie, aby odpowiednio śledzić to, co się dzieje.
UWAGA Zdarzenia umożliwiają korzystanie z różnych stylów trwałości i zapytań, takich jak Event Sourcing oraz Command Query Responsibility Segregation (CQRS). Nie są one prerekwizytami dla mikroserwisów, ale mają pewną synergię z podejściem mikroserwisowym. Przeanalizujemy to w rozdziale 5.
Rysunek 3.11. Zdarzeniowa asynchroniczna komunikacja między usługami
Komunikacja asynchroniczna zwykle wymaga brokera komunikacji, niezależnego komponentu systemu, który odbiera zdarzenia i dystrybuuje je do ich odbiorców. Jest to czasami nazywane kręgosłupem zdarzeń, co wskazuje, jak centralnym elementem aplikacji staje się ten komponent (rys. 3.11). Narzędzia powszechnie używane jako brokerzy to Kafka, RabbitMQ i Redis. Semantyka tych narzędzi jest różna – Kafka specjalizuje się w wielostrumieniowym, odtwarzalnym magazynie zdarzeń, podczas gdy RabbitMQ zapewnia oprogramowanie pośredniczące do komunikacji na wyższych poziomach (oparte na protokole AMQP (https://www.amqp.org/)).
3.4.3. Wzorce komunikacji asynchronicznej
Przyjrzyjmy się dwóm najczęstszym wzorcom opartym na zdarzeniach: kolejce zadań i publish-subscribe. Spotkasz się z tymi wzorcami podczas projektowania mikroserwisów – najbardziej zaawansowane wzorce interakcji są zbudowane na jednym z tych dwóch prymitywów.
KOLEJKA