Czy Microservices powinny ze sobą rozmawiać?

30

Projektuję aplikację przy użyciu Mikro-usług i nie jestem pewien, jaki jest najlepszy mechanizm gromadzenia danych z wielu usług.

Wierzę, że są dwie opcje:

  • Zintegruj mechanizm komunikacji „między usługami”, który umożliwia usługom bezpośrednią rozmowę. Interfejs API Gateway wywoływałby pojedynczą usługę, która następnie wywołuje inne usługi w celu gromadzenia danych, zanim zwróci skonsolidowaną odpowiedź do interfejsu API Gateway. Interfejs API zwraca odpowiedź do osoby dzwoniącej. (Musiałyby to być połączenia synchroniczne, gdy połączenie z usługą B wymaga odpowiedzi od usługi A. IE Oddziel osobę i usługi adresowe.)
  • Niech brama API wywołuje bezpośrednio każdą usługę i konsoliduje dane w interfejsie API przed zwróceniem odpowiedzi.

Opieram się na drugiej opcji, ponieważ rozmowa między usługami wprowadziłaby sprzężenie, w którym to przypadku równie dobrze mogłabym po prostu zaprojektować aplikację monolityczną. Istnieje jednak kilka poważnych wad, które mogę oderwać od głowy z tą opcją:

  • Posiadanie przez API wykonywania wielu wywołań do wielu usług zwiększa obciążenie serwera API, szczególnie gdy niektóre z tych połączeń są blokowane.

  • Ta metoda oznaczałaby, że interfejs API musiałby być „świadomy” tego, co aplikacja próbuje zrobić (IE Logic musiałaby zostać zaprogramowana w interfejsie API, aby obsługiwała wywoływanie usług, a następnie konsolidację danych), a nie tylko działają jak głupi „punkt końcowy” dla mikrousług.

Chciałbym wiedzieć, jakie jest standardowe podejście do tego problemu i czy istnieje inna trzecia opcja, której mi brakuje?

KidCode
źródło
Czy możesz podać jakiś kontekst? Jaka jest twoja aplikacja i co próbuje zrobić
Ewan
Domyślam się, że są gdzieś pomiędzy dwiema opcjami: każda mikrousługa komunikuje się z innymi mikrousługami w razie potrzeby, aby wykonać swoją pracę. Bramę API można również uznać za mikrousługę, która przede wszystkim przekazuje pracę innym usługom.
Bart van Ingen Schenau
Twierdziłbym, że komponowanie mikrousług po stronie serwera jest sprzeczne z głównym celem posiadania mikrousług na początek. Cały pomysł polega na uniezależnieniu usług i pozostawieniu aranżacji klientowi. Ale może jestem niepraktyczny
Sridhar Sarnobat

Odpowiedzi:

21

Ogólnie odradzam, aby mikrousługi wykonywały synchroniczną komunikację ze sobą, dużym problemem jest łączenie, oznacza to, że usługi są teraz połączone ze sobą, jeśli jedna z nich zawiedzie, druga jest teraz całkowicie lub częściowo niefunkcjonalna.

Zrobiłbym wyraźne rozróżnienie między operacjami zmieniającymi stan a operacjami odczytu (CQS Command Query Separation ). Do operacji zmieniających stan użyłbym infrastruktury komunikacyjnej i wziąłbym ogień i zapomniał. W przypadku zapytań użyjesz komunikacji synchronicznej odpowiedzi na żądanie i możesz użyć interfejsu API HTTP lub po prostu przejść bezpośrednio do magazynu danych.

Jeśli używasz przesyłania wiadomości, możesz także spojrzeć na subskrypcję publikowania w celu zgłaszania zdarzeń między usługami.

Inną kwestią do rozważenia jest (transakcyjne) udostępnianie danych (w przeciwieństwie do widoków tylko do odczytu), jeśli ujawnisz swój stan wewnętrzny, czytelnik może uzyskać niewłaściwy stan twoich danych lub niewłaściwą wersję, a także potencjalnie zablokuje twoje dane?

Na koniec staraj się robić wszystko, co w twojej mocy, aby twoje usługi były autonomiczne (przynajmniej na poziomie logicznym).

Mam nadzieję, że to ma sens.

Sean Farmar
źródło
11

To zależy od tego, dlaczego potrzebujesz tych danych. Jeśli chodzi o interfejs użytkownika, to jest całkowicie w porządku. Co więcej, tak powinno być. Chris Richardson ma ładne wyjaśnienie tej koncepcji , a Sam Newman ma świetny artykuł na temat bardzo podobnej koncepcji o nazwie Backends for Frontends .

Ale jeśli potrzebujesz go do jakiejś logiki, istnieje prawdopodobieństwo, że granice usług są nieprawidłowe.

Zdrowy rozsądek mówi nam, że nasze usługi powinny posiadać kilka cech . Oni są:

  1. Niskie sprzęgło. Jeśli wprowadzisz jakieś zmiany w usłudze A, nie chcesz, aby miały one wpływ na usługę B.
  2. Wysoka spójność. Jeśli chcesz wdrożyć jakąś funkcję, chcesz wpłynąć na jak najmniejszą liczbę usług.
  3. Wysoka autonomia. Jeśli niektóre usługi ulegną awarii, nie chcesz, aby cały system był wyłączony.
  4. Prawidłowa ziarnistość. Nie chcesz, aby twoje usługi były zbyt rozmowne, ponieważ twoja sieć jest bardziej złożona niż mogłoby się wydawać.
  5. Usługi powinny komunikować się za pośrednictwem wydarzeń. Nie chcesz, aby twoja usługa była świadoma siebie nawzajem, ponieważ zmniejsza to łatwość konserwacji. Zastanów się, co się stanie, jeśli chcesz dodać nową usługę.
  6. Zdecentralizowane dane. Usługa nie powinna udostępniać sposobu przechowywania informacji. Podobnie jak dobry obiekt, odsłania zachowanie, a nie dane.
  7. Choreografia serwisowa nad orkiestracją.

Aby to osiągnąć, traktuj granice swoich usług jako możliwości biznesowe . Formalny proces identyfikowania granic usług wygląda następująco:

  1. Zidentyfikuj granice wyższego poziomu. Lubię myśleć o nich jako o krokach, przez które Twoja organizacja powinna przejść, aby osiągnąć swój cel biznesowy, aby uzyskać wartość biznesową. Możesz pomyśleć o podstawowych krokach, patrząc na łańcuch wartości Portera .
  2. W ramach każdej usługi sięgaj głębiej. Zidentyfikuj samodzielne jednostki dziecka z ich własnymi obowiązkami.
  3. Uważaj na sposób, w jaki się komunikują. Prawidłowe usługi komunikują się przede wszystkim poprzez zdarzenia. Pomyśl o swojej strukturze organizacyjnej. Komunikacja w nich jest dość intensywna, choć zwykle ujawnia się kilka zdarzeń zewnętrznych.

Przykładem zastosowania tego podejścia może być z pewnym zainteresowaniem.

Zapadło
źródło
1

Domyślam się również na drugie podejście, choć może nie w „bramie API”, ale uważam za całkowicie rozsądne stworzenie nowej mikrousługi, której jedynym celem było koordynowanie żądań do innych mikrousług i reprezentowanie dane w formie wyższego poziomu. W architekturze mikrousług opierałbym się na tym, aby mikrousługi „podstawowe” komunikowały się bezpośrednio ze sobą.

Aby uczynić to nieco mniej subiektywnym, powiedzmy, że jedna usługa zależy od drugiej, jeśli pierwsza wymaga danych lub usług od drugiej, bezpośrednio lub pośrednio . Pod względem matematycznym chcemy, aby ta relacja była częściowym porządkiem, a nie zamówieniem przedpremierowym . W formie diagramu, jeśli narysowałeś diagram zależności, powinieneś otrzymać diagram Hassegoi nie mają żadnych (ukierunkowanych) cykli. (Na diagramie Hassego krawędzie są domyślnie skierowane od dołu do góry.) Kolejną wskazówką jest, aby ścieżki od góry do dołu były na ogół krótsze. Oznacza to, że chcesz bardziej zależeć domyślnie od rzeczy. Powodem jest to, że minimalizuje liczbę rzeczy, które mogą pójść nie tak w przypadku konkretnego żądania, minimalizuje koszty ogólne i zmniejsza złożoność. Tak więc w „idealnym” przypadku według tej metryki diagram Hassego miałby tylko dwa poziomy. Oczywiście istnieje wiele powodów, dla których warto wprowadzić usługi pośrednie, takie jak buforowanie, konsolidacja, równoważenie obciążenia, zarządzanie awariami.

Aby rozwinąć twoją drugą troskę o to, aby brama API była „inteligentna”, wzorcem, który zyskuje teraz na popularności w ramach takich jak Falcor i Relay / GraphQL, jest zwiększenie wymagań specyfikacji, aby „API Gateway” ogólnie wykonać te specyfikacje, nie wiedząc, co się z tym GetTimelinewiąże. Zamiast tego otrzyma żądanie takie jak „poproś o te informacje użytkownika z usługi użytkownika i uzyskaj te posty z usługi poczty” lub cokolwiek innego.

Derek Elkins
źródło
0

Podejrzewam, że potrzeba wzajemnego połączenia usług wskazuje na to, że korzystasz z systemu, który nie został dobrze skonstruowany, ponieważ potrzeba wzajemnego połączenia mikrousług jest formą łączenia, która rzadko pojawia się, gdy mikrousług są odpowiednio zaprojektowane.

Czy potrafisz wyjaśnić więcej na temat problemu, który próbujesz rozwiązać? Prosto po angielsku?

Ben
źródło