Читать книгу Mikroserwisy w akcji - Группа авторов - Страница 37

Część 2
Projekt
3. Architektura aplikacji mikroserwisowej
3.5. Granica aplikacji

Оглавление

Warstwa granicy stanowi fasadę w stosunku do złożonych interakcji wewnętrznych usług. Klienci, na przykład aplikacje mobilne, webowe interfejsy użytkownika lub urządzenia IoT, mogą wchodzić w interakcję z aplikacją mikroserwisową. (Można budować tych klientów samodzielnie lub mogą je tworzyć inne podmioty korzystające z publicznego interfejsu API naszej aplikacji). Na przykład SimpleBank, jak pokazano na rysunku 3.16, ma wewnętrzne narzędzia administracyjne, witrynę inwestycyjną, aplikacje na iOS i Androida oraz publiczny interfejs API.


Rysunek 3.16. Aplikacje klienckie w SimpleBank


Warstwa graniczna zapewnia abstrakcyjność nad wewnętrzną złożonością i zmiennością (rys. 3.17). Można na przykład zapewnić spójny interfejs dla klienta, który będzie wyświetlał listę wszystkich zleceń historycznych, ale z czasem można całkowicie zreorganizować wewnętrzną implementację tej funkcjonalności. Bez tej warstwy klienci wymagaliby zbyt dużej wiedzy na temat poszczególnych usług i byliby ściśle związani z implementacją systemu.


Rysunek 3.17. Granica stanowi fasadę nad warstwą usług, aby ukryć przed konsumentem wewnętrzną złożoność


Poza tym, warstwa graniczna zapewnia dostęp do danych i funkcjonalności przy użyciu komunikacji i rodzaju treści odpowiedniej dla konsumenta. Na przykład, podczas gdy usługi mogą komunikować się między sobą za pomocą gRPC, fasada może udostępniać HTTP API zewnętrznym konsumentom, co jest znacznie bardziej odpowiednie dla nich do zastosowania.

Połączenie tych ról pozwala aplikacji stać się czarną skrzynką, wykonującą dowolne operacje (nieznane klientowi) w celu zaoferowania funkcjonalności. Z większą pewnością można także wprowadzać zmiany w warstwie usług, ponieważ klient łączy się z nią za pośrednictwem pojedynczego punktu.

Warstwa granicy może również implementować inne zdolności przeznaczone dla klientów:

uwierzytelnianie i autoryzacja – aby zweryfikować tożsamość i uprawnienia klienta API;

ograniczanie liczby odpowiedzi – aby zapewnić ochronę przed nadużyciami klientów;

buforowanie – aby zmniejszyć ogólne obciążenie backendu;

■ zbieranie dzienników i metryk – aby umożliwić analizę i monitorowanie żądań klientów.

Umieszczenie tych krańcowych zdolności w warstwie granicznej zapewnia ich wyraźny rozdział – bez granicy usługi backendowe musiałyby indywidualnie implementować te zdolności, zwiększając tym samym swoją złożoność.

Granic można także użyć na poziomie usług, aby oddzielić ich domeny. Na przykład proces składania zleceń może się składać z kilku usług, ale tylko jedna z nich powinna udostępniać punkt dostępu, do którego byłby dostęp z innych domen (rys. 3.18).


Rysunek 3.18. Granice mogą występować między różnymi kontekstami w aplikacji mikroserwisowej


UWAGA  Wewnętrzne granice usługi często odzwierciedlają ograniczone konteksty – spójne, ograniczone podzbiory ogólnego zakresu aplikacji. Omówimy je dokładniej w następnym rozdziale.

To tylko przegląd możliwości zastosowania granic. Bądźmy bardziej konkretni i przyjrzyjmy się bliżej trzem różnym (choć powiązanym) wzorcom dla granic aplikacji: bramom API, bramom consumer-driven oraz backends for frontends.

3.5.1. Bramy API

Wzorzec bramy API wprowadziliśmy w rozdziale 2. Zapewnia on klientowi pojedynczy punkt dostępu w stosunku do zaplecza opartego na usługach. Pośredniczy w przekazywaniu żądań do zasadniczych usług i przekształca ich odpowiedzi. Brama API może obsługiwać inne, przekrojowe oczekiwania klientów, takie jak uwierzytelnianie i podpisywanie żądań.

WSKAZÓWKA  Dostępne bramy API występują w postaci zarówno narzędzi open source, jak na przykład Mashape’s Kong, a także jako produkty komercyjne, jak na przykład AWS API Gateway.

Na rysunku 3.19 przedstawiono bramę API. Brama uwierzytelnia żądanie, a jeśli to się powiedzie, przesyła żądanie do odpowiedniej usługi backendu. Następnie przekształca otrzymane wyniki, tak że po ich zwróceniu są one w postaci odpowiedniej dla klientów.

Z perspektywy bezpieczeństwa brama pozwala także zminimalizować narażony na ryzyko obszar systemu, umieszczając wewnętrzne usługi w sieci prywatnej i ograniczając dostęp dla wszystkich, oprócz bramy.

OSTRZEŻENIE  Czasami brama API może wykonywać kompozycję – złożenie w jedną odpowiedzi z wielu usług. Linia między tym a agregacją warstwy usług jest rozmyta. Najlepiej zachować ostrożność i unikać przeciekania logiki biznesowej do samej bramy, co może nadmiernie zwiększać wiązanie między bramą a usługami podstawowymi.

Rysunek 3.19. Brama API obsługująca żądanie klienta


3.5.2. Backends for frontends

Wzorzec backends for frontends (BFF) jest odmianą podejścia opartego na bramie API. Chociaż podejście oparte na bramie API jest eleganckie, ma kilka wad. Jeśli działa ona jako punkt kompozycyjny dla wielu aplikacji, zaczyna brać na siebie większą odpowiedzialność.

Wyobraźmy sobie na przykład, że obsługujemy zarówno aplikacje stacjonarne, jak i mobilne. Urządzenia mobilne mają inne potrzeby, wyświetlając mniej danych przy mniejszej przepustowości i dostępnych innych funkcjonalnościach użytkownika, takich jak lokalizacja i kontekst. W praktyce oznacza to, że potrzeby urządzeń stacjonarnych i mobilnych dotyczące interfejsu API są rozbieżne, co zwiększa zakres funkcjonalności potrzebnych do integracji w bramie. Różne potrzeby, takie jak ilość danych (a tym samym ilość istotnych informacji) zwróconych dla danego zasobu, mogą również powodować konflikty. Może być trudno zrównoważyć te przeciwstawne oczekiwania podczas budowania spójnego i zoptymalizowanego interfejsu API.

W podejściu BFF używamy bram API dla każdego typu obsługiwanego klienta. Biorąc wcześniejszy przykład z SimpleBanku, każda usługa dostępna dla użytkownika miałaby unikalną bramę (rys. 3.20).


Rysunek 3.20. Wzorzec backends for frontends dla aplikacji klienckich SimpleBanku


Dzięki temu brama może być bardzo specyficzna i reagować na potrzeby jej klientów bez konfliktów czy konieczności jej nadmiernej rozbudowy. Skutkuje to mniejszymi i prostszymi bramami oraz ich bardziej ukierunkowanym rozwojem.

3.5.3. Bramy consumer-driven

W obu poprzednich wzorcach to brama API określała strukturę danych, które zwraca konsumentowi. Aby obsługiwać różnych klientów, można tworzyć unikalne backendy. Odwróćmy to jednak. Co by się stało, gdybyśmy mogli zbudować bramkę, która pozwoliłaby konsumentom dokładnie określić, jakich danych potrzebują od naszej usługi? Pomyślmy o tym jak o ewolucji podejścia BFF – zamiast budować wiele interfejsów API, można zbudować pojedynczy superzestaw API, który pozwala konsumentom zdefiniować kształt odpowiedzi, której oczekuje.

Możemy to osiągnąć za pomocą GraphQL. GraphQL jest językiem zapytań dla interfejsów API, który pozwala konsumentom na określenie, których pól danych potrzebują, oraz na łączenie różnych zasobów w pojedynczym żądaniu. Na przykład dla klientów SimpleBanku moglibyśmy udostępnić następujący schemat.

Listing 3.1. Prosty schemat GraphQL dla SimpleBanku

type Account {

id: ID!

! wskazuje, że pole nie może być puste

name: String!

currentHoldings: [Holding]!

Rachunek zawiera listy Holding i Order (Aktywa i Zlecenie)

orders: [Order]!

}

type Order {

id: ID!

status: String!

asset: Asset!

quantity: Float!

}

type Holding {

asset: Asset!

quantity: Float!

}

type Asset {

id: ID!

name: String!

type: String!

price: Float!

}

type Root {

accounts: [Account]!

Zwraca wszystkie rachunki lub rachunek zgodny z identyfikatorem

account(id: ID): Account

}

schema: {

query: Root

Schemat ma pojedynczy punkt dostępu dla zapytań

}

Ten schemat udostępnia rachunki klientów, a także zlecenia i aktywa na każdym z tych rachunków. Klienci następnie wykonują zapytania na tym schemacie. Jeśli na ekranie aplikacji mobilnej są wyświetlane informacje o aktywach i niezrealizowanych zleceniach dla rachunku, można pobrać te dane w jednym żądaniu, jak pokazano na poniższym listingu.

Listing 3.2. Treść żądania z użyciem GraphQL

{

account(id: "101") {

Filtrowanie rachunków według ID

orders

Żądanie określonych pól składowych w odpowiedzi

currentHoldings

}

}

W backendzie serwer GraphQL działałby jak brama API, przekierowując i łącząc dane z wielu usług (w tym przypadku zleceń i aktywów). W tej książce nie będziemy szczegółowo drążyć GraphQL, ale dla zainteresowanych oficjalna dokumentacja (http://graphql.org/) jest świetnym miejscem do rozpoczęcia. Odnieślibyśmy także sukces, korzystając z Apollo (https://www.apollographql.com/), aby zapewnić fasadę GraphQL API w stosunku do usług RESTful backend.

Mikroserwisy w akcji

Подняться наверх