Obsługa wiadomości w architekturze zorientowanej na usługi

(Joan Zapata) (8 grudnia 2020 r.)

Architektura zorientowana na usługi (SOA) dowiodła jego mocne strony w praktycznie wszystkich gałęziach przemysłu do produkcji skalowalnych i ewolucyjnych systemów. SOA ma wiele znaczeń, ale podstawowa idea podziału złożonej aplikacji na mniejsze, wielokrotnego użytku i luźno powiązane usługi przeszła długą drogę od późnych lat 90. Podjęliśmy tę koncepcję od pierwszego dnia i po trzech latach mamy obecnie około dwudziestu niezależnych usług opartych na domenach, które tworzą strukturę naszych aplikacji zaplecza. Pozwoliło nam to używać języków, które lubiliśmy – takich jak Kotlin , Elixir – oraz narzędzi chcieliśmy – jak pozyskiwanie informacji o zdarzeniach – do wykonania danego zadania.

Jednak posiadanie wielu usług wiąże się z własnymi wyzwaniami, z których pierwszy to jak sprawić, by usługi komunikowały się ze sobą ? Istnieje wiele strategii, a ten artykuł jest podsumowaniem doświadczeń z tych, których używamy w Memo Bank.

Zacznijmy od dwóch usług i tego prostego przypadku użycia jako przykładu:

REST przez HTTPS

Podobnie jak wiele innych aplikacji zaplecza, rozpoczęliśmy od REST wywołań przez HTTPS.

Cykliczne zależności między usługami należy za wszelką cenę unikać, więc umowy nie może bezpośrednio powiedzieć klientom , aby aktywowali nowego klienta zaraz po podpisaniu umowy. Zamiast tego klienci muszą regularnie wysyłać żądania do umów , aby wiedzieć, kiedy zadanie jest zakończone.

HTTPS to świetny początek i zdecydowanie coś, co warto zachować w zestawie narzędzi: jest prosty w konfiguracji, szeroko obsługiwany i używany również do udostępniania interfejsów API aplikacjom frontendowym. Ale jest jeden poważny problem z tym schematem, jest to synchroniczny (chociaż niekoniecznie blokujący). Oznacza to, że podczas gdy umowy działają, klienci czekają z aktywnym połączeniem. W przypadku użycia na dużą skalę oznacza to, że najwolniejsza usługa może spowolnić cały system. Oznacza to również, że gdy usługa kontraktów jest niedostępna, usługa klientów również nie jest, co nazywa się kaskadową awarią.

Jak sobie poradziliśmy ten przypadek? Użyliśmy dwóch różnych wzorców: dyskretnego i ciągłego przesyłania wiadomości.

Dyskretne przesyłanie wiadomości

Weźmy pierwszy przypadek użycia: klienci chcą umów do wysłania umowy.

W tym celu możemy rozwiązać problem za pomocą mechanizmu przesyłania wiadomości dyskretnych: queues . Możesz zobaczyć kolejkę jako skrzynkę pocztową innej firmy o wysokiej dostępności. Nawet jeśli główna usługa jest niedostępna, skrzynka pocztowa przyjmuje wiadomości. Wiele wystąpień tej samej usługi może korzystać z tej samej kolejki. W takim przypadku kolejka działa jako moduł równoważenia obciążenia i zapewnia, że ​​każdy komunikat jest obsługiwany co najmniej raz. Po obsłużeniu wiadomości skrzynka pocztowa może o niej zapomnieć.

Używamy kolejek do wysyłania poleceń (np. „SendContract”) z jednej usługi do drugiej. Ma kilka zalet:

  • Usługa dzwoniącego nie polega na dostępności z usługa odbierająca i może wznowić swoją pracę, gdy tylko polecenie znajdzie się w kolejce;
  • Odbiornik może obsługiwać polecenia we własnym tempie i możemy łatwo skalować usługę odbiorcy w górę lub w dół w zależności od obciążenia jego kolejek;
  • Jako bonus, błąd można łatwo wyizolować i rozwiązać ręcznie (mamy nadzieję, że temat kolejki utraconych wiadomości omówimy w innym artykule).

Ciągłe przesyłanie wiadomości

Teraz przyjrzyjmy się drugiemu przypadkowi użycia, kiedy umowa jest podpisywana, umowy muszą informować o tym klientów tak się stało, że może aktywować klienta.

Kuszące jest użycie tutaj innej kolejki, ale jak powiedzieliśmy wcześniej, nie chcemy cyklicznej zależności, więc umowy nie wiedzą byle co o klientach . Dlatego nie może wysłać polecenia „ActivateCustomer” i nie może wiedzieć, kiedy i gdzie wysłać to polecenie.

Rozwiązaliśmy ten problem za pomocą mechanizmu ciągłego przesyłania wiadomości: strumienie .Możesz zobaczyć strumień jako uporządkowaną sekwencję zdarzeń, które można wykorzystać w czasie rzeczywistym, ale są również udostępniane w czasie. W przeciwieństwie do kolejek, które są niepowiązanymi poleceniami efemerycznymi, strumienie przekazują trwającą historię .

Każda usługa w Memo Bank transmituje strumień events opisujące cykl życia jego zasobów. Tworzenie i utrzymywanie tych zdarzeń jest integralną częścią każdego rozwoju , niezależnie od tego, czy to wydarzenie jest natychmiast potrzebne. Jest to część procedury, podobnie jak testy automatyczne i metryki.

W ten sposób zdarzenia te stają się wiarygodnym logiem z sygnaturą czasową niezmienny fakty . A ponieważ są częścią API usługi emitującej, mogą być konsumowane przez każdą inną usługę, zarówno w czasie rzeczywistym (pojedynczo), jak iw przyszłości. Te zdarzenia mają ogromną wartość dla identyfikowalności i analizy danych .

Podsumowując:

  • Kolejki służą do wysyłania poleceń do konkretna usługa;
  • Strumienie służą do ujawnienia faktów z konkretną usługę.

Wszystko o zależnościach

Powyższy diagram może sprawić, że będziesz się zastanawiać, patrząc na strzałki, czy nie wprowadza cykliczna zależność między klientami a umowami ?

Nie. Zależność nie jest definiowana przez kierunek danych, ale przez wzajemne usługi wiedzy. Tutaj klient wie o umowach , mówi mu, co ma robić i wysłuchuje jego historii. Ale kontrakt nic nie wie o klientach , nie musi wiedzieć, kto wysyła polecenia ani kto słucha jego historii.

Oba kolejka i strumień są częścią kontraktów API, a klienci są zależni od tego interfejsu API.

Posiadanie nazewnictwa konwencja poleceń i faktów jest bardzo ważna, aby przekazać tę ideę. Zawsze używamy formy podstawowej dla poleceń, na przykład „SendContract”, oraz formy imiesłowów przeszłych dla faktów, np. „ContractSent”.

Zauważ, że jest to dogodnie dopasowane do naszej architektury podstawowego systemu bankowego w oparciu o CQRS / ES . W tej terminologii polecenia są takie same, a zdarzenia to fakty.

Jak wybrać kierunek zależności

Biorąc pod uwagę zasady wyjaśnione wcześniej, to rozwiązanie byłoby równie ważne:

Ale jeśli oba rozwiązania są prawidłowe, jak wybrać jedno z nich? Cóż, to zależy od Ciebie.

Wszystko sprowadza się do kierunku zależności , jaki chcesz do ustawienia.

A: klienci zależą od umów . B: kontrakty zależą od klientów .

Oto kilka pytań, które zwykle sobie zadajemy:

  • Czy jedna usługa może łatwo być agnostyczna względem innych?
    Tutaj na przykład, o ile udostępniamy treść kontraktom , kontrakty mogą być całkowicie niezależne od tego, która usługa ich używa. Trudniej jest sobie wyobrazić, że klienci są agnostyczni co do tego, że wymaga to umowy. To na korzyść A.
  • A co by było, gdyby jedna usługa była stroną trzecią?
    Dla na przykład nie miałoby sensu zlecanie przez Memo Bank klientów outsourcingu, ale mogłoby to robić w przypadku umów . Dlatego jest to również korzystne dla A.
  • Czy jedna usługa organizuje inne usługi?
    Niejawna orkiestracja jest zła, więcej na jej temat można znaleźć w tym wykładzie Bernda Rueckera. Tworzenie klienta to złożony przepływ pracy , który obejmuje wiele usług (wysyłanie e-maili, powiadomień, tworzenie konta bankowego itp.), Więc prawdopodobnie klienci są tutaj koordynatorem.Uzależnienie koordynatora od innych usług – a nie odwrotnie – znacznie ułatwia zrozumienie kodu, ponieważ pełny przepływ pracy można znaleźć w jednym miejscu. Jest to również korzystne dla A.
  • Czy tworzy to cykl w całej architekturze?
    Nawet jeśli nie ma połączenia między tymi dwiema usługami, obie zależą od innych usług. Powiedzmy, że klienci są uzależnieni od użytkowników , a użytkownicy są już uzależnieni od umów . Gdybyśmy wybrali rozwiązanie B, stworzyłoby to cykl z trzema usługami. To również przemawia na korzyść A.

Podsumowanie

Wiadomości są jednym z pierwszych pytań, na które musimy odpowiedzieć podczas tworzenia architektury zorientowanej na usługi. Korzystanie z HTTPS i REST wydaje się początkowo najprostszym rozwiązaniem, ale ma swoje ograniczenia. Uzupełniliśmy nasz arsenał o kolejki i strumienie i ustaliliśmy głównie dwie wytyczne.

Po pierwsze, każda usługa powinna przesyłać strumieniowo zdarzenia , gdy zdarzają się fakty w ramach tej usługi, nawet jeśli nie są one jeszcze potrzebne. Te zdarzenia powinny informować historię o tym, co dzieje się w usłudze, np. „ContractSent”, „ContractSigned”. Jest to świetne rozwiązanie do śledzenia – które jest wymagane jako bank – ale także do konsolidacji API każdej usługi i do ułatwienia pracy z systemem dla wszystkich zespołów.

Po drugie, chodzi o zależności . Zależności kształtują system, a cykliczne zależności są wrogiem numer jeden. Po prawidłowym ustawieniu zależności narzędzia do przesyłania wiadomości są dostępne po to, aby umożliwić przepływ danych w dowolnym kierunku.

Pierwotnie opublikowane pod adresem https://memo.bank/en/magazine .

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *