Wzorzec bramy interfejsu API a bezpośrednia komunikacja między mikrousługami

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.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

W architekturze mikrousług każda mikrousług uwidacznia zestaw (zazwyczaj) precyzyjnych punktów końcowych. Ten fakt może mieć wpływ na komunikację między klientem a mikrousługą, jak wyjaśniono w tej sekcji.

Bezpośrednia komunikacja między klientem a mikrousługą

Możliwe jest użycie bezpośredniej architektury komunikacji między klientem a mikrousługą. W tym podejściu aplikacja kliencka może wysyłać żądania bezpośrednio do niektórych mikrousług, jak pokazano na rysunku 4–12.

Diagram showing client-to-microservice communication architecture.

Rysunek 4–12. Używanie bezpośredniej architektury komunikacji między klientem a mikrousługą

W tym podejściu każda mikrousługa ma publiczny punkt końcowy, czasami z innym portem TCP dla każdej mikrousługi. Przykładem adresu URL dla określonej usługi może być następujący adres URL na platformie Azure:

http://eshoponcontainers.westus.cloudapp.azure.com:88/

W środowisku produkcyjnym opartym na klastrze ten adres URL będzie mapować na moduł równoważenia obciążenia używany w klastrze, co z kolei dystrybuuje żądania między mikrousługi. W środowiskach produkcyjnych można mieć kontroler dostarczania aplikacji (ADC), taki jak aplikacja systemu Azure Gateway między mikrousługami a Internetem. Ta warstwa działa jako przezroczysta warstwa, która nie tylko wykonuje równoważenie obciążenia, ale zabezpiecza usługi, oferując kończenie żądań SSL. Takie podejście poprawia obciążenie hostów przez odciążanie żądań SSL intensywnie korzystających z procesora CPU i innych obowiązków związanych z routingiem do usługi aplikacja systemu Azure Gateway. W każdym razie moduł równoważenia obciążenia i usługa ADC są niewidoczne z punktu widzenia architektury aplikacji logicznej.

Bezpośrednia architektura komunikacji między klientem a mikrousługą może być wystarczająca dla małej aplikacji opartej na mikrousługach, zwłaszcza jeśli aplikacja kliencka jest aplikacją internetową po stronie serwera, na przykład aplikacją MVC ASP.NET. Jednak podczas tworzenia dużych i złożonych aplikacji opartych na mikrousługach (na przykład w przypadku obsługi kilkudziesięciu typów mikrousług), a zwłaszcza gdy aplikacje klienckie są zdalnymi aplikacjami mobilnymi lub aplikacjami internetowymi SPA, to podejście ma kilka problemów.

Podczas tworzenia dużej aplikacji na podstawie mikrousług należy wziąć pod uwagę następujące pytania:

  • Jak aplikacje klienckie mogą zminimalizować liczbę żądań do zaplecza i zmniejszyć komunikację z wieloma mikrousługami?

Interakcja z wieloma mikrousługami w celu utworzenia jednego ekranu interfejsu użytkownika zwiększa liczbę rund w Internecie. Takie podejście zwiększa opóźnienie i złożoność po stronie interfejsu użytkownika. W idealnym przypadku odpowiedzi powinny być efektywnie agregowane po stronie serwera. Takie podejście zmniejsza opóźnienie, ponieważ wiele fragmentów danych wraca równolegle, a niektóre interfejsy użytkownika mogą wyświetlać dane natychmiast po ich gotowości.

  • W jaki sposób można obsługiwać kwestie obejmujące krzyżowe, takie jak autoryzacja, przekształcenia danych i dynamiczne wysyłanie żądań?

Implementowanie zabezpieczeń i zagadnień obejmujących wiele zagadnień, takich jak zabezpieczenia i autoryzacja dla każdej mikrousługi, może wymagać znacznego nakładu pracy programistycznej. Możliwe jest użycie tych usług na hoście platformy Docker lub klastrze wewnętrznym w celu ograniczenia bezpośredniego dostępu do nich z zewnątrz oraz zaimplementowania tych problemów krzyżowych w scentralizowanym miejscu, na przykład w usłudze API Gateway.

  • W jaki sposób aplikacje klienckie mogą komunikować się z usługami korzystającymi z protokołów niezwiązanych z Internetem?

Protokoły używane po stronie serwera (takie jak protokół AMQP lub protokoły binarne) nie są obsługiwane w aplikacjach klienckich. W związku z tym żądania muszą być wykonywane za pośrednictwem protokołów, takich jak HTTP/HTTPS, i tłumaczone na inne protokoły później. Podejście man-in-the-middle może pomóc w tej sytuacji.

  • Jak można kształtować fasadę specjalnie utworzoną dla aplikacji mobilnych?

Interfejs API wielu mikrousług może nie być dobrze zaprojektowany pod kątem potrzeb różnych aplikacji klienckich. Na przykład potrzeby aplikacji mobilnej mogą być inne niż potrzeby aplikacji internetowej. W przypadku aplikacji mobilnych może być konieczne jeszcze bardziej zoptymalizowane, aby odpowiedzi na dane mogły być bardziej wydajne. Możesz to zrobić, agregując dane z wielu mikrousług i zwracając pojedynczy zestaw danych, a czasami eliminując wszelkie dane w odpowiedzi, które nie są potrzebne przez aplikację mobilną. Oczywiście możesz skompresować te dane. Ponownie fasada lub interfejs API między aplikacją mobilną a mikrousługami mogą być wygodne w tym scenariuszu.

Dlaczego warto rozważyć użycie bram interfejsu API zamiast bezpośredniej komunikacji między klientem a mikrousługą

W architekturze mikrousług aplikacje klienckie zwykle muszą korzystać z funkcji z więcej niż jednej mikrousługi. Jeśli to użycie jest wykonywane bezpośrednio, klient musi obsługiwać wiele wywołań do punktów końcowych mikrousługi. Co się stanie w przypadku rozwoju aplikacji i wprowadzenia nowych mikrousług lub zaktualizowania istniejących mikrousług? Jeśli aplikacja ma wiele mikrousług, obsługa tak wielu punktów końcowych z aplikacji klienckich może być koszmarem. Ponieważ aplikacja kliencka zostanie połączona z tymi wewnętrznymi punktami końcowymi, rozwój mikrousług w przyszłości może spowodować duży wpływ na aplikacje klienckie.

W związku z tym posiadanie pośredniego lub warstwy pośredniej (bramy) może być wygodne dla aplikacji opartych na mikrousługach. Jeśli nie masz bram interfejsu API, aplikacje klienckie muszą wysyłać żądania bezpośrednio do mikrousług i zgłaszać problemy, takie jak następujące problemy:

  • Sprzęganie: bez wzorca usługi API Gateway aplikacje klienckie są powiązane z wewnętrznymi mikrousługami. Aplikacje klienckie muszą wiedzieć, jak wiele obszarów aplikacji jest rozłożonych w mikrousługach. Podczas ewolucji i refaktoryzacji wewnętrznych mikrousług te wpływają na konserwację, ponieważ powodują one niezgodność zmian w aplikacjach klienckich z powodu bezpośredniego odwołania do wewnętrznych mikrousług z aplikacji klienckich. Aplikacje klienckie muszą być często aktualizowane, co utrudnia rozwijanie rozwiązania.

  • Zbyt wiele rund: pojedyncza strona/ekran w aplikacji klienckiej może wymagać kilku wywołań wielu usług. Takie podejście może spowodować wiele rund sieci między klientem a serwerem, dodając znaczne opóźnienie. Agregacja obsługiwana na poziomie pośrednim może zwiększyć wydajność i środowisko użytkownika aplikacji klienckiej.

  • Problemy z zabezpieczeniami: bez bramy wszystkie mikrousługi muszą być widoczne dla "świata zewnętrznego", co powoduje, że atak jest większy niż w przypadku ukrycia wewnętrznych mikrousług, które nie są bezpośrednio używane przez aplikacje klienckie. Tym mniejsza jest powierzchnia ataku, tym bezpieczniejsza może być aplikacja.

  • Obawy dotyczące krzyżowania: Każda publicznie opublikowana mikrousługa musi obsługiwać takie problemy jak autoryzacja i protokół SSL. W wielu sytuacjach te obawy mogą być obsługiwane w jednej warstwie, dzięki czemu wewnętrzne mikrousługi są uproszczone.

Jaki jest wzorzec bramy interfejsu API?

Podczas projektowania i kompilowania dużych lub złożonych aplikacji opartych na mikrousługach z wieloma aplikacjami klienckimi dobrym rozwiązaniem może być brama interfejsu API. Ten wzorzec jest usługą, która zapewnia pojedynczy punkt wejścia dla niektórych grup mikrousług. Jest on podobny do wzorca fasady z projektu zorientowanego obiektowo, ale w tym przypadku jest częścią systemu rozproszonego. Wzorzec bramy interfejsu API jest również czasami nazywany "zapleczem frontonu" (BFF), ponieważ tworzysz go podczas myślenia o potrzebach aplikacji klienckiej.

W związku z tym brama interfejsu API znajduje się między aplikacjami klienckimi a mikrousługami. Działa jako zwrotny serwer proxy, rozsyłanie żądań od klientów do usług. Może również udostępniać inne funkcje krzyżowe, takie jak uwierzytelnianie, kończenie żądań SSL i pamięć podręczna.

Rysunek 4–13 pokazuje, jak niestandardowa brama interfejsu API może zmieścić się w uproszczonej architekturze opartej na mikrousługach z zaledwie kilkoma mikrousługami.

Diagram showing an API Gateway implemented as a custom service.

Rysunek 4–13. Używanie bramy interfejsu API zaimplementowanej jako usługa niestandardowa

Aplikacje łączą się z pojedynczym punktem końcowym, bramą interfejsu API, który jest skonfigurowany do przekazywania żądań do poszczególnych mikrousług. W tym przykładzie brama interfejsu API zostanie zaimplementowana jako niestandardowa usługa ASP.NET Core WebHost działająca jako kontener.

Ważne jest, aby podkreślić, że na tym diagramie będziesz używać jednej niestandardowej usługi API Gateway, która ma wiele i różne aplikacje klienckie. Może to być ważne ryzyko, ponieważ usługa API Gateway będzie rozwijać się i ewoluować w oparciu o wiele różnych wymagań aplikacji klienckich. Ostatecznie zostanie on wzdęty ze względu na te różne potrzeby i skutecznie może być podobny do aplikacji monolitycznej lub usługi monolitycznej. Dlatego zdecydowanie zaleca się podzielenie bramy interfejsu API w wielu usługach lub wielu mniejszych bram interfejsów API, na przykład jeden na typ formularza aplikacji klienckiej.

Podczas implementowania wzorca bramy interfejsu API należy zachować ostrożność. Zazwyczaj nie jest dobrym pomysłem, aby jedna brama interfejsu API agreguje wszystkie wewnętrzne mikrousługi aplikacji. Jeśli tak, działa jako agregator monolityczny lub orkiestrator i narusza autonomię mikrousług przez sprzężenie wszystkich mikrousług.

W związku z tym bramy interfejsu API powinny być segregowane na podstawie granic biznesowych i aplikacji klienckich, a nie działać jako pojedynczy agregator dla wszystkich wewnętrznych mikrousług.

Podczas dzielenia warstwy bramy interfejsu API na wiele bram interfejsów API, jeśli aplikacja ma wiele aplikacji klienckich, może to być podstawowy element przestawny podczas identyfikowania wielu typów bram interfejsu API, dzięki czemu można mieć inną fasadę dla potrzeb każdej aplikacji klienckiej. Ten przypadek jest wzorcem o nazwie "Backend for Frontend" (BFF), w którym każda brama interfejsu API może zapewnić inny interfejs API dostosowany do każdego typu aplikacji klienckiej, być może nawet na podstawie współczynnika formularza klienta przez zaimplementowanie określonego kodu karty, który pod spodem wywołuje wiele wewnętrznych mikrousług, jak pokazano na poniższej ilustracji:

Diagram showing multiple custom API Gateways.

Rysunek 4–13.1. Używanie wielu niestandardowych bram interfejsu API

Rysunek 4–13.1 przedstawia bramy interfejsu API podzielone według typu klienta; jeden dla klientów mobilnych i jeden dla klientów internetowych. Tradycyjna aplikacja internetowa łączy się z mikrousługą MVC korzystającą z internetowej bramy interfejsu API. W przykładzie przedstawiono uproszczoną architekturę z wieloma precyzyjnymi bramami interfejsu API. W takim przypadku granice zidentyfikowane dla każdej bramy interfejsu API są oparte wyłącznie na wzorcu "Zaplecze dla frontonu" (BFF), w związku z tym oparte tylko na interfejsie API wymaganym dla aplikacji klienckiej. Jednak w większych aplikacjach należy również przejść dalej i utworzyć inne bramy interfejsu API oparte na granicach biznesowych jako drugi element przestawny projektowania.

Główne funkcje w wzorcu bramy interfejsu API

Brama interfejsu API może oferować wiele funkcji. W zależności od produktu może oferować bogatsze lub prostsze funkcje, jednak najważniejsze i podstawowe funkcje dla każdej bramy api są następującymi wzorcami projektowymi:

Zwrotny routing serwera proxy lub bramy. Brama interfejsu API oferuje zwrotny serwer proxy do przekierowywania lub kierowania żądań (routing warstwy 7, zazwyczaj żądań HTTP) do punktów końcowych wewnętrznych mikrousług. Brama udostępnia pojedynczy punkt końcowy lub adres URL dla aplikacji klienckich, a następnie wewnętrznie mapuje żądania na grupę wewnętrznych mikrousług. Ta funkcja routingu pomaga oddzielić aplikacje klienckie od mikrousług, ale jest również wygodna podczas modernizacji monolitycznego interfejsu API, siedząc bramę interfejsu API między monolitycznym interfejsem API a aplikacjami klienckimi, a następnie można dodać nowe interfejsy API jako nowe mikrousługi, a jednocześnie korzystać ze starszego interfejsu API monolitycznego, dopóki nie zostanie ona podzielona na wiele mikrousług w przyszłości. Ze względu na bramę interfejsu API aplikacje klienckie nie będą zauważać, czy używane interfejsy API są implementowane jako wewnętrzne mikrousługi lub monolityczny interfejs API, a co ważniejsze, podczas ewolucji i refaktoryzacji monolitycznego interfejsu API do mikrousług dzięki routingowi usługi API Gateway aplikacje klienckie nie będą mieć wpływu na żadną zmianę identyfikatora URI.

Aby uzyskać więcej informacji, zobacz Wzorzec routingu bramy.

Agregacja żądań. W ramach wzorca bramy można agregować wiele żądań klienta (zazwyczaj żądań HTTP) przeznaczonych dla wielu wewnętrznych mikrousług w jednym żądaniu klienta. Ten wzorzec jest szczególnie wygodny, gdy strona/ekran klienta potrzebuje informacji z kilku mikrousług. Dzięki temu aplikacja kliencka wysyła pojedyncze żądanie do bramy interfejsu API, która wysyła kilka żądań do wewnętrznych mikrousług, a następnie agreguje wyniki i wysyła wszystko z powrotem do aplikacji klienckiej. Główną korzyścią i celem tego wzorca projektowego jest zmniejszenie rozmów między aplikacjami klienckimi a interfejsem API zaplecza, co jest szczególnie ważne w przypadku zdalnych aplikacji z centrum danych, w którym działają mikrousługi, takie jak aplikacje mobilne lub żądania pochodzące z aplikacji SPA pochodzących z języka JavaScript w przeglądarkach zdalnych klienta. W przypadku zwykłych aplikacji internetowych wykonujących żądania w środowisku serwera (takich jak aplikacja internetowa ASP.NET Core MVC), ten wzorzec nie jest tak ważny, ponieważ opóźnienie jest znacznie mniejsze niż w przypadku zdalnych aplikacji klienckich.

W zależności od używanego produktu usługi API Gateway może być możliwe przeprowadzenie tej agregacji. Jednak w wielu przypadkach bardziej elastyczne jest tworzenie mikrousług agregacji w zakresie bramy interfejsu API, więc można zdefiniować agregację w kodzie (czyli kod C#):

Aby uzyskać więcej informacji, zobacz Wzorzec agregacji bramy.

Problemy związane z przecięciem krzyżowym lub odciążanie bramy. W zależności od funkcji oferowanych przez poszczególne produkty usługi API Gateway można odciążyć funkcje poszczególnych mikrousług do bramy, co upraszcza implementację każdej mikrousługi przez konsolidację zagadnień krzyżowych w jednej warstwie. Takie podejście jest szczególnie wygodne w przypadku wyspecjalizowanych funkcji, które mogą być złożone w celu prawidłowego wdrożenia w każdej wewnętrznej mikrousłudze, takiej jak następujące funkcje:

  • Uwierzytelnianie i autoryzacja
  • Integracja odnajdywania usług
  • Buforowanie odpowiedzi
  • Zasady ponawiania, wyłącznik i QoS
  • Ograniczanie szybkości i ograniczanie przepustowości
  • Równoważenie obciążenia
  • Rejestrowanie, śledzenie, korelacja
  • Nagłówki, ciągi zapytania i przekształcenia oświadczeń
  • Lista dozwolonych adresów IP

Aby uzyskać więcej informacji, zobacz Wzorzec odciążania bramy.

Używanie produktów z funkcjami usługi API Gateway

W zależności od każdej implementacji może istnieć wiele innych problemów oferowanych przez produkty usługi API Gateway. Przyjrzymy się tutaj:

Usługa Azure API Management

Usługa Azure API Management (jak pokazano na rysunku 4–14) nie tylko rozwiązuje potrzeby usługi API Gateway, ale udostępnia funkcje takie jak zbieranie szczegółowych informacji z interfejsów API. Jeśli używasz rozwiązania API Management, brama interfejsu API jest tylko składnikiem w ramach tego pełnego rozwiązania do zarządzania interfejsami API.

Diagram showing how to use Azure API Management as your API gateway.

Rysunek 4–14. Korzystanie z usługi Azure API Management dla bramy interfejsu API

Usługa Azure API Management rozwiązuje potrzeby bramy interfejsu API i zarządzania, takie jak rejestrowanie, zabezpieczenia, pomiary itp. W takim przypadku w przypadku korzystania z produktu takiego jak Usługa Azure API Management fakt, że może istnieć jedna brama interfejsu API, nie jest tak ryzykowna, ponieważ tego rodzaju bramy interfejsu API są "cieńsze", co oznacza, że nie implementujesz niestandardowego kodu języka C#, który może ewoluować w kierunku składnika monolitycznego.

Produkty usługi API Gateway zwykle działają jak zwrotny serwer proxy dla komunikacji przychodzącej, gdzie można również filtrować interfejsy API z wewnętrznych mikrousług oraz stosować autoryzację do opublikowanych interfejsów API w tej warstwie pojedynczej.

Szczegółowe informacje dostępne w systemie usługi API Management pomagają zrozumieć, jak są używane interfejsy API i jak działają. Wykonują one te działania, umożliwiając wyświetlanie raportów analizy w czasie rzeczywistym i identyfikowanie trendów, które mogą mieć wpływ na Twoją firmę. Ponadto możesz mieć dzienniki dotyczące działań dotyczących żądań i odpowiedzi w celu dalszej analizy online i offline.

Usługa Azure API Management umożliwia zabezpieczanie interfejsów API przy użyciu klucza, tokenu i filtrowania adresów IP. Te funkcje umożliwiają wymuszanie elastycznych i precyzyjnych przydziałów i limitów szybkości, modyfikowanie kształtu i zachowania interfejsów API przy użyciu zasad oraz zwiększanie wydajności dzięki buforowaniu odpowiedzi.

W tym przewodniku i przykładowej aplikacji referencyjnej (eShopOnContainers) architektura jest ograniczona do prostszej i niestandardowej architektury konteneryzowanej, aby skupić się na zwykłych kontenerach bez używania produktów PaaS, takich jak Usługa Azure API Management. Jednak w przypadku dużych aplikacji opartych na mikrousługach wdrożonych na platformie Microsoft Azure zachęcamy do oceny usługi Azure API Management jako podstawy dla bram interfejsu API w środowisku produkcyjnym.

Ocelot

Ocelot to uproszczona brama interfejsu API zalecana w przypadku prostszych podejść. Ocelot to oparta na platformie .NET Core brama interfejsu API typu open source, szczególnie dla architektur mikrousług, które wymagają ujednoliconych punktów wejścia do swoich systemów. Jest lekki, szybki i skalowalny oraz zapewnia routing i uwierzytelnianie wśród wielu innych funkcji.

Głównym powodem wybrania rozwiązania Ocelot dla aplikacji referencyjnej eShopOnContainers 2.0 jest to, że rozwiązanie Ocelot jest uproszczoną bramą interfejsu API platformy .NET Core, którą można wdrożyć w tym samym środowisku wdrażania aplikacji, w którym wdrażasz mikrousługi/kontenery, takie jak host platformy Docker, platforma Kubernetes itp. A ponieważ jest oparta na platformie .NET Core, jest to międzyplatformowa platforma umożliwiająca wdrażanie w systemie Linux lub Windows.

Poprzednie diagramy przedstawiające niestandardowe bramy interfejsu API działające w kontenerach są dokładnie sposobem uruchamiania rozwiązania Ocelot w aplikacji opartej na kontenerach i mikrousług.

Ponadto na rynku dostępnych jest wiele innych produktów oferujących funkcje bram API Gateway, takie jak Apigee, Kong, MuleSoft, WSO2 i inne produkty, takie jak Linkerd i Istio dla funkcji kontrolera ruchu przychodzącego siatki usług.

Po początkowych sekcjach objaśnień architektury i wzorców w następnych sekcjach opisano sposób implementowania bram interfejsu API za pomocą rozwiązania Ocelot.

Wady wzorca bramy interfejsu API

  • Najważniejszą wadą jest to, że podczas implementowania bramy interfejsu API sprzężenie tej warstwy z wewnętrznymi mikrousługami. Takie sprzężenie może spowodować poważne problemy z aplikacją. Clemens Vaster, architekt zespołu usługi Azure Service Bus, odnosi się do tego potencjalnego trudności jako "nowego ESB" w sesji "Obsługa komunikatów i mikrousług" na GOTO 2016.

  • Użycie bramy interfejsu API mikrousług powoduje utworzenie dodatkowego możliwego pojedynczego punktu awarii.

  • Brama interfejsu API może wprowadzić zwiększony czas odpowiedzi ze względu na dodatkowe wywołanie sieciowe. Jednak to dodatkowe wywołanie zwykle ma mniejszy wpływ niż interfejs klienta, który jest zbyt czatty bezpośrednio wywołując wewnętrzne mikrousługi.

  • Jeśli brama API Gateway nie zostanie prawidłowo przeskalowana w poziomie, może stać się wąskim gardłem.

  • Brama interfejsu API wymaga dodatkowych kosztów programowania i przyszłej konserwacji, jeśli obejmuje niestandardową logikę i agregację danych. Deweloperzy muszą zaktualizować bramę interfejsu API, aby uwidocznić punkty końcowe każdej mikrousługi. Ponadto zmiany implementacji w wewnętrznych mikrousług mogą spowodować zmiany kodu na poziomie bramy interfejsu API. Jeśli jednak brama interfejsu API stosuje tylko zabezpieczenia, rejestrowanie i przechowywanie wersji (tak jak w przypadku korzystania z usługi Azure API Management), ten dodatkowy koszt programowania może nie mieć zastosowania.

  • Jeśli usługa API Gateway jest opracowywana przez jeden zespół, może wystąpić wąskie gardło programistyczne. Ten aspekt jest kolejnym powodem, dla którego lepszym rozwiązaniem jest posiadanie kilku precyzyjnych bram interfejsów API, które odpowiadają na różne potrzeby klientów. Bramę interfejsu API można również podzielić wewnętrznie na wiele obszarów lub warstw należących do różnych zespołów pracujących nad wewnętrznymi mikrousługami.

Dodatkowe zasoby