Asynchroniczna komunikacja oparta na komunikatach

Napiwek

Ta zawartość jest fragmentem książki eBook, architektury mikrousług platformy .NET dla konteneryzowanych aplikacji platformy .NET dostępnych na platformie .NET Docs lub jako bezpłatnego pliku PDF, który można odczytać w trybie offline.

Architektura mikrousług platformy .NET dla konteneryzowanych aplikacji platformy .NET — miniatura książki eBook.

Asynchroniczne komunikaty i komunikacja sterowana zdarzeniami mają kluczowe znaczenie podczas propagacji zmian w wielu mikrousług i powiązanych modelach domeny. Jak wspomniano wcześniej w omówieniu mikrousług i powiązanych kontekstów (BCs), modele (użytkownik, klient, produkt, konto itp.) mogą oznaczać różne elementy dla różnych mikrousług lub kontrolerów domeny. Oznacza to, że w przypadku wystąpienia zmian potrzebne są pewne sposoby uzgadniania zmian w różnych modelach. Rozwiązaniem jest spójność ostateczna i komunikacja oparta na zdarzeniach oparta na asynchronicznych komunikatach.

W przypadku korzystania z komunikatów procesy komunikują się asynchronicznie przez wymianę komunikatów. Klient wysyła polecenie lub żądanie do usługi, wysyłając do niej komunikat. Jeśli usługa musi odpowiedzieć, wysyła inną wiadomość z powrotem do klienta. Ponieważ jest to komunikacja oparta na komunikatach, klient zakłada, że odpowiedź nie zostanie odebrana natychmiast i że w ogóle nie będzie żadnej odpowiedzi.

Komunikat składa się z nagłówka (metadanych, takich jak identyfikacja lub informacje zabezpieczające) i treści. Komunikaty są zwykle wysyłane za pośrednictwem protokołów asynchronicznych, takich jak AMQP.

Preferowaną infrastrukturą dla tego typu komunikacji w społeczności mikrousług jest lekki broker komunikatów, który różni się od dużych brokerów i orkiestratorów używanych w SOA. W lekkim brokerze komunikatów infrastruktura jest zwykle "głupia", działając tylko jako broker komunikatów, z prostymi implementacjami, takimi jak RabbitMQ lub skalowalna magistrala usług w chmurze, taka jak Azure Service Bus. W tym scenariuszu większość "inteligentnego" myślenia nadal znajduje się w punktach końcowych, które generują i zużywają komunikaty, czyli w mikrousługach.

Kolejną regułą, którą należy wykonać, jak najwięcej, jest użycie tylko asynchronicznej obsługi komunikatów między usługami wewnętrznymi i używania komunikacji synchronicznej (takiej jak HTTP) tylko z aplikacji klienckich do usług frontonu (bramy interfejsu API oraz pierwszy poziom mikrousług).

Istnieją dwa rodzaje asynchronicznej komunikacji komunikatów: komunikacja oparta na komunikatach pojedynczego odbiorcy i komunikacja oparta na komunikatach wielu odbiorników. Poniższe sekcje zawierają szczegółowe informacje o nich.

Komunikacja oparta na komunikatach z jednym odbiornikiem

Komunikacja asynchroniczna oparta na komunikatach z jednym odbiornikiem oznacza, że istnieje komunikacja punkt-punkt, która dostarcza komunikat do dokładnie jednego z odbiorców odczytu z kanału i że komunikat jest przetwarzany tylko raz. Istnieją jednak szczególne sytuacje. Na przykład w systemie w chmurze, który próbuje automatycznie odzyskać odzyskiwanie po awariach, ten sam komunikat może zostać ponownie wysłany wiele razy. Z powodu awarii sieci lub innych, klient musi mieć możliwość ponawiania próby wysyłania komunikatów, a serwer musi zaimplementować operację, która ma być idempotentna , aby przetworzyć określony komunikat tylko raz.

Komunikacja oparta na komunikatach z jednym odbiornikiem jest szczególnie odpowiednia do wysyłania asynchronicznych poleceń z jednej mikrousługi do innej, jak pokazano na rysunku 4–18, który ilustruje to podejście.

Po rozpoczęciu wysyłania komunikacji opartej na komunikatach (za pomocą poleceń lub zdarzeń) należy unikać mieszania komunikacji opartej na komunikatach z synchroniczną komunikacją HTTP.

Pojedyncza mikrousługa odbierający komunikat asynchroniczny

Rysunek 4–18. Pojedyncza mikrousługa odbierający komunikat asynchroniczny

Gdy polecenia pochodzą z aplikacji klienckich, można je zaimplementować jako polecenia synchroniczne HTTP. Użyj poleceń opartych na komunikatach, gdy potrzebujesz większej skalowalności lub gdy jesteś już w procesie biznesowym opartym na komunikatach.

Komunikacja oparta na komunikatach z wieloma odbiornikami

Bardziej elastyczne podejście może również chcieć użyć mechanizmu publikowania/subskrybowania , dzięki czemu komunikacja od nadawcy będzie dostępna dla dodatkowych mikrousług subskrybentów lub aplikacji zewnętrznych. W związku z tym pomaga przestrzegać zasady otwierania/zamykania w usłudze wysyłającej. Dzięki temu dodatkowi subskrybenci mogą zostać dodani w przyszłości bez konieczności modyfikowania usługi nadawcy.

W przypadku korzystania z komunikacji publikowania/subskrybowania możesz użyć interfejsu magistrali zdarzeń do publikowania zdarzeń dla dowolnego subskrybenta.

Asynchroniczna komunikacja sterowana zdarzeniami

W przypadku korzystania z komunikacji asynchronicznej opartej na zdarzeniach mikrousługa publikuje zdarzenie integracji, gdy coś dzieje się w swojej domenie, a inna mikrousługa musi być o tym świadoma, podobnie jak zmiana ceny w mikrousłudze katalogu produktów. Dodatkowe mikrousługi subskrybują zdarzenia, aby mogły otrzymywać je asynchronicznie. W takim przypadku odbiorcy mogą aktualizować własne jednostki domeny, co może spowodować opublikowanie większej liczby zdarzeń integracji. Ten system publikowania/subskrybowania jest wykonywany przy użyciu implementacji magistrali zdarzeń. Magistrala zdarzeń może być zaprojektowana jako abstrakcja lub interfejs z interfejsem API wymaganym do subskrybowania lub anulowania subskrypcji zdarzeń oraz publikowania zdarzeń. Magistrala zdarzeń może również mieć jedną lub więcej implementacji na podstawie dowolnego brokera między procesami i komunikatami, takiego jak kolejka obsługi komunikatów lub magistrala usług, która obsługuje komunikację asynchroniczną i model publikowania/subskrybowania.

Jeśli system używa spójności ostatecznej opartej na zdarzeniach integracji, zaleca się, aby takie podejście było jasne dla użytkownika końcowego. System nie powinien używać podejścia, które naśladuje zdarzenia integracji, takie jak SignalR lub systemy sondowania od klienta. Użytkownik końcowy i właściciel firmy muszą jawnie przyjąć spójność ostateczną w systemie i zdać sobie sprawę, że w wielu przypadkach firma nie ma żadnego problemu z tym podejściem, o ile jest to jawne. Takie podejście jest ważne, ponieważ użytkownicy mogą oczekiwać natychmiastowego wyświetlenia niektórych wyników, a ten aspekt może nie wystąpić ze spójnością ostateczną.

Jak wspomniano wcześniej w sekcji Wyzwania i rozwiązania dotyczące rozproszonego zarządzania danymi, można użyć zdarzeń integracji do implementowania zadań biznesowych obejmujących wiele mikrousług. W związku z tym będziesz mieć spójność ostateczną między tymi usługami. Ostatecznie spójna transakcja składa się z kolekcji akcji rozproszonych. W każdej akcji powiązana mikrousługa aktualizuje jednostkę domeny i publikuje kolejne zdarzenie integracji, które wywołuje następną akcję w ramach tego samego kompleksowego zadania biznesowego.

Ważnym punktem jest to, że możesz chcieć komunikować się z wieloma mikrousługami, które są subskrybowane do tego samego zdarzenia. W tym celu można użyć komunikatów publikowania/subskrybowania na podstawie komunikacji sterowanej zdarzeniami, jak pokazano na rysunku 4–19. Ten mechanizm publikowania/subskrybowania nie jest wyłączny dla architektury mikrousług. Jest on podobny do sposobu, w jaki konteksty ograniczone w DDD powinny komunikować się lub sposób propagacji aktualizacji z bazy danych zapisu do bazy danych odczytu w wzorcu architektury Command and Query Responsibility Segion (CQRS). Celem jest zapewnienie spójności ostatecznej między wieloma źródłami danych w systemie rozproszonym.

Diagram przedstawiający asynchroniczną komunikację sterowaną zdarzeniami.

Rysunek 4–19. Asynchroniczna komunikacja komunikatów sterowana zdarzeniami

W asynchronicznej komunikacji opartej na zdarzeniach jedna mikrousługa publikuje zdarzenia w magistrali zdarzeń i wiele mikrousług może je subskrybować, aby otrzymywać powiadomienia i wykonywać na nim działania. Implementacja określi protokół używany do komunikacji opartej na zdarzeniach. Protokół AMQP może pomóc w osiągnięciu niezawodnej komunikacji w kolejce.

Ilość danych do udostępnienia w tych zdarzeniach jest kolejnym ważnym zagadnieniem, zarówno identyfikatorem, jak i różnymi elementami danych biznesowych. Te zagadnienia zostały omówione w tym wpisie w blogu na temat zdarzeń integracji cienkich i tłuszczu.

Jeśli używasz magistrali zdarzeń, możesz użyć poziomu abstrakcji (na przykład interfejsu magistrali zdarzeń) na podstawie powiązanej implementacji w klasach z kodem przy użyciu interfejsu API z brokera komunikatów, takiego jak RabbitMQ lub magistrala usług, na przykład Usługa Azure Service Bus z tematami. Alternatywnie możesz użyć magistrali usług wyższego poziomu, takiej jak NServiceBus, MassTransit lub Brighter , aby przedstawić magistralę zdarzeń i opublikować/subskrybować system.

Uwaga dotycząca technologii obsługi komunikatów dla systemów produkcyjnych

Technologie obsługi komunikatów dostępne do implementowania abstrakcyjnej magistrali zdarzeń są na różnych poziomach. Na przykład produkty takie jak RabbitMQ (transport brokera obsługi komunikatów) i Azure Service Bus znajdują się na niższym poziomie niż inne produkty, takie jak NServiceBus, MassTransit lub Brighter, które mogą pracować na platformie RabbitMQ i Azure Service Bus. Wybór zależy od liczby rozbudowanych funkcji na poziomie aplikacji i skalowalności gotowej do użycia w aplikacji. Aby zaimplementować tylko magistralę zdarzeń weryfikacji koncepcji dla środowiska projektowego, tak jak zostało to zrobione w przykładzie eShopOnContainers, prosta implementacja na platformie RabbitMQ uruchomiona w kontenerze platformy Docker może wystarczyć.

Jednak w przypadku systemów o znaczeniu krytycznym i produkcyjnym, które wymagają hiper-skalowalności, warto ocenić usługę Azure Service Bus. W przypadku abstrakcji i funkcji wysokiego poziomu, które ułatwiają tworzenie aplikacji rozproszonych, zalecamy ocenę innych komercyjnych i open source magistrali usług, takich jak NServiceBus, MassTransit i Brighter. Oczywiście możesz tworzyć własne funkcje magistrali usług na podstawie technologii niższego poziomu, takich jak RabbitMQ i Docker. Jednak praca wodociągowa może kosztować zbyt wiele w przypadku niestandardowej aplikacji dla przedsiębiorstw.

Odporne publikowanie w magistrali zdarzeń

Wyzwaniem podczas implementowania architektury opartej na zdarzeniach w wielu mikrousług jest sposób niepodzielnej aktualizacji stanu oryginalnej mikrousługi podczas odpornego publikowania powiązanego zdarzenia integracji w magistrali zdarzeń, w jakiś sposób na podstawie transakcji. Poniżej przedstawiono kilka sposobów na osiągnięcie tej funkcji, chociaż mogą istnieć również dodatkowe podejścia.

  • Używanie kolejki transakcyjnej (opartej na dtC), takiej jak MSMQ. (Jednak jest to starsze podejście).

  • Korzystanie z wyszukiwania dzienników transakcji.

  • Używanie pełnego wzorca określania źródła zdarzeń.

  • Za pomocą wzorca outbox: tabela transakcyjnej bazy danych jako kolejka komunikatów, która będzie bazą dla składnika twórcy zdarzeń, który utworzy zdarzenie i opublikuje je.

Aby uzyskać bardziej szczegółowy opis wyzwań w tej przestrzeni, w tym sposób publikowania komunikatów z potencjalnie niepoprawnymi danymi, zobacz Platforma danych dla obciążeń o znaczeniu krytycznym na platformie Azure: każdy komunikat musi być przetwarzany.

Dodatkowe tematy, które należy wziąć pod uwagę podczas korzystania z komunikacji asynchronicznej, to idempotencja komunikatów i deduplikacja komunikatów. Te tematy zostały omówione w sekcji Implementowanie komunikacji opartej na zdarzeniach między mikrousługami (zdarzeniami integracji) w dalszej części tego przewodnika.

Dodatkowe zasoby