Używanie bramy w celu agregowania wielu indywidualnych żądań w pojedynczym żądaniu. Ten wzorzec jest przydatny, gdy klient musi skierować wiele wywołań do różnych systemów zaplecza w celu wykonania operacji.
Kontekst i problem
Aby wykonać jedno zadanie, może być konieczne skierowanie wielu wywołań do różnych usług zaplecza. Aplikacja, która korzysta z wielu usług w celu wykonania zadania, musi używać zasobów przy każdym żądaniu. Dodanie nowych funkcji lub usług do aplikacji powoduje, że rośnie liczba potrzebnych żądań, co dodatkowo zwiększa wymagania dotyczące zasobów i liczbę wywołań sieci. Duża liczba operacji między klientem a zapleczem może niekorzystnie wpłynąć na wydajności i skalę aplikacji. Architektury oparte na mikrousługach upowszechniły ten problem, ponieważ aplikacje utworzone wokół wielu mniejszych usług w naturalny sposób wymagają większej liczby wywołań między usługami.
Na poniższym diagramie klient wysyła żądania do poszczególnych usług (1, 2, 3). Każda usługa przetwarza żądanie i wysyła odpowiedź z powrotem do aplikacji (4, 5, 6). W sieci komórkowej, którą zwykle wyróżnia duże opóźnienie, takie wysyłanie poszczególnych żądań jest nieefektywne i może spowodować przerwanie łączności lub pojawienie się niekompletnych żądań. Chociaż transmisja poszczególnych żądań może odbywać się równolegle, aplikacja musi je wysłać, poczekać, a następnie przetworzyć dane za pośrednictwem osobnych połączeń, co zwiększa ryzyko wystąpienia awarii.
Rozwiązanie
Brama umożliwia ograniczenie liczby operacji między klientem i usługami. Brama odbiera żądania klienta, rozsyła je do różnych systemów zaplecza, a następnie agreguje wyniki i wysyła je z powrotem do klienta.
Ten wzorzec może zmniejszyć liczbę żądań wysyłanych przez aplikację do usług zaplecza, zwiększając wydajność aplikacji w sieciach z dużym opóźnieniem.
Na poniższym diagramie aplikacja wysyła żądanie do bramy (1). Żądanie to zawiera pakiet dodatkowych żądań. Brama je rozkłada i przetwarza, wysyłając poszczególne żądania do odpowiednich usług (2). Każda usługa zwraca odpowiedź do bramy (3). Brama łączy odpowiedzi od poszczególnych usług i wysyła zagregowaną odpowiedź do aplikacji (4). Aplikacja wysyła jedno żądanie i odbiera tylko jedną odpowiedź od bramy.
Problemy i kwestie do rozważenia
- Brama nie powinna wprowadzać sprzężenia między usługami zaplecza.
- Brama powinna znajdować się w pobliżu usług zaplecza w celu maksymalnego zmniejszenia opóźnień.
- Usługa bramy może stanowić pojedynczy punkt awarii. Brama musi zostać prawidłowo zaprojektowana pod kątem wymagań dotyczących dostępności aplikacji.
- Brama może stanowić wąskie gardło. Upewnij się, że brama ma odpowiednią wydajność, zapewniającą obsługę obciążenia, i że można ją skalować w odpowiedzi na rosnące potrzeby.
- Wykonaj testowanie obciążenia bramy, aby mieć pewność, że nie występują kaskadowe awarie usług.
- Zaimplementuj odporny projekt przy użyciu technik, takich jak grodzie, wyłączniki, ponawianie i limity czasu.
- Jeśli co najmniej jedno wywołanie usługi trwa zbyt długo, może być dopuszczalne przekroczenie limitu czasu i zwrócenie częściowego zestawu danych. Zastanów się, jak aplikacja poradzi sobie w tym scenariuszu.
- Używaj asynchronicznych operacji we/wy, aby zagwarantować, że opóźnienie na zapleczu nie spowoduje problemów z wydajnością aplikacji.
- W celu śledzenia poszczególnych wywołań zaimplementuj rozproszone śledzenie z użyciem identyfikatorów korelacji.
- Monitoruj metryki żądań i rozmiary odpowiedzi.
- W ramach strategii trybu failover służącej do obsługi błędów zastanów się nad zwracaniem buforowanych danych.
- Zamiast wdrażania agregacji w bramie, umieść usługę agregacji za bramą. Agregacja żądań prawdopodobnie będzie mieć inne wymagania dotyczące zasobów niż pozostałe usługi w bramie. Agregacja może mieć wpływ na funkcje routingu i odciążania bramy.
Kiedy używać tego wzorca
Użyj tego wzorca, gdy:
- W celu wykonania operacji klient musi komunikować się z wieloma usługami zaplecza.
- Klient może używać sieci charakteryzujących się znacznym opóźnieniem, takich jak sieć komórkowa.
Ten wzorzec może być nieodpowiedni w następujących przypadkach:
- Chcesz zmniejszyć liczbę wywołań między klientem a pojedynczą usługą w wielu operacjach. W tym scenariuszu lepszym rozwiązaniem może okazać się dodanie operacji zbiorczej do usługi.
- Klient lub aplikacja znajduje się w pobliżu usług zaplecza, a opóźnienie nie jest istotnym czynnikiem.
Projekt obciążenia
Architekt powinien ocenić, w jaki sposób wzorzec agregacji bramy może być używany w projekcie obciążenia, aby sprostać celom i zasadom opisanym w filarach platformy Azure Well-Architected Framework. Na przykład:
Filar | Jak ten wzorzec obsługuje cele filaru |
---|---|
Decyzje projektowe dotyczące niezawodności pomagają obciążeniu stać się odporne na awarię i zapewnić, że zostanie przywrócony do w pełni funkcjonalnego stanu po wystąpieniu awarii. | Ta topologia umożliwia między innymi przesunięcie obsługi błędów przejściowych z implementacji rozproszonej między klientami do scentralizowanej implementacji. - RE:07 Błędy przejściowe |
Decyzje dotyczące projektowania zabezpieczeń pomagają zapewnić poufność, integralność i dostępność danych i systemów obciążenia. | Ta topologia często zmniejsza liczbę punktów dotykowych, które klient ma w systemie, co zmniejsza obszar powierzchni publicznej i punkty uwierzytelniania. Zagregowane zaplecza mogą pozostać w pełni odizolowane od sieci od klientów. - Segmentacja SE:04 - SE:08 Wzmacnianie zabezpieczeń |
Doskonałość operacyjna pomaga zapewnić jakość obciążeń dzięki ustandaryzowanym procesom i spójności zespołu. | Ten wzorzec umożliwia ewolucję logiki zaplecza niezależnie od klientów, co umożliwia zmianę implementacji usługi łańcuchowej, a nawet źródeł danych bez konieczności zmieniania punktów dotykowych klienta. - OE:04 Narzędzia i procesy |
Wydajność pomaga wydajnie sprostać zapotrzebowaniu dzięki optymalizacjom skalowania, danych, kodu. | Ten projekt może spowodować mniejsze opóźnienie niż projekt, w którym klient nawiązuje wiele połączeń. Buforowanie w implementacjach agregacji minimalizuje wywołania systemów zaplecza. - PE:03 Wybieranie usług - PE:08 Wydajność danych |
Podobnie jak w przypadku każdej decyzji projektowej, należy rozważyć wszelkie kompromisy w stosunku do celów innych filarów, które mogą zostać wprowadzone przy użyciu tego wzorca.
Przykład
Poniższy przykład przedstawia tworzenie prostej usługi NGINX służącej do agregacji bramy przy użyciu skryptu Lua.
worker_processes 4;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location = /batch {
content_by_lua '
ngx.req.read_body()
-- read json body content
local cjson = require "cjson"
local batch = cjson.decode(ngx.req.get_body_data())["batch"]
-- create capture_multi table
local requests = {}
for i, item in ipairs(batch) do
table.insert(requests, {item.relative_url, { method = ngx.HTTP_GET}})
end
-- execute batch requests in parallel
local results = {}
local resps = { ngx.location.capture_multi(requests) }
for i, res in ipairs(resps) do
table.insert(results, {status = res.status, body = cjson.decode(res.body), header = res.header})
end
ngx.say(cjson.encode({results = results}))
';
}
location = /service1 {
default_type application/json;
echo '{"attr1":"val1"}';
}
location = /service2 {
default_type application/json;
echo '{"attr2":"val2"}';
}
}
}