Powtarzaj za mną:
REST i zdarzenia asynchroniczne nie są alternatywami. Są całkowicie ortogonalne.
Możesz mieć jedno, drugie, jedno i drugie lub jedno i drugie. Są to całkowicie różne narzędzia dla zupełnie różnych domen problemowych. W rzeczywistości komunikacja typu żądanie-odpowiedź ogólnego przeznaczenia jest absolutnie w stanie być asynchroniczna, sterowana zdarzeniami i odporna na uszkodzenia .
Jako trywialny przykład protokół AMQP wysyła wiadomości przez połączenie TCP. W TCP każdy pakiet musi być potwierdzony przez odbiornik . Jeśli nadawca pakietu nie otrzyma potwierdzenia ACK dla tego pakietu, wysyła go ponownie do momentu potwierdzenia lub do momentu, gdy warstwa aplikacji „zrezygnuje” i porzuci połączenie. Jest to oczywiście nietolerancyjny model żądanie-odpowiedź, ponieważ każde „żądanie wysłania pakietu” musi mieć towarzyszącą „odpowiedź na potwierdzenie pakietu”, a brak odpowiedzi skutkuje niepowodzeniem całego połączenia. Jednak AMQP, znormalizowany i powszechnie przyjęty protokół asynchronicznego przesyłania komunikatów odpornych na uszkodzenia, jest komunikowany przez TCP! Co daje?
Podstawową koncepcją w tym przypadku jest to, że skalowalne luźno powiązane, odporne na awarie wiadomości są definiowane przez to, jakie wiadomości wysyłasz , a nie jak je wysyłasz . Innymi słowy, luźne połączenie jest definiowane na warstwie aplikacyjnej .
Spójrzmy na dwie strony komunikujące się bezpośrednio z RESTful HTTP lub pośrednio z brokerem komunikatów AMQP. Załóżmy, że strona A chce przesłać obraz JPEG do strony B, która wyostrzy, skompresuje lub w inny sposób poprawi obraz. Grupa A nie potrzebuje natychmiast przetworzonego obrazu, ale wymaga odwołania do niego w celu przyszłego wykorzystania i pobrania. Oto jeden ze sposobów, który może iść w REST:
- Strona A wysyła
POST
komunikat żądania HTTP do Strony B za pomocąContent-Type: image/jpeg
- Strona B przetwarza obraz (przez długi czas, jeśli jest duży), podczas gdy Strona A czeka, prawdopodobnie robiąc inne rzeczy
- Strona B wysyła
201 Created
komunikat odpowiedzi HTTP do Strony A z Content-Location: <url>
nagłówkiem, który prowadzi do przetworzonego obrazu
- Strona A uważa swoją pracę za wykonaną, ponieważ ma teraz odniesienie do przetworzonego obrazu
- W przyszłości, gdy strona A potrzebuje przetworzonego obrazu, Pobiera go za pomocą linku z wcześniejszego
Content-Location
nagłówka
201 Created
Kod odpowiedzi mówi klientowi, że nie tylko ich wniosek udany, stworzyła również nowy zasób. W odpowiedzi 201 Content-Location
nagłówek jest linkiem do utworzonego zasobu. Jest to określone w sekcjach 6.3.2 i 3.1.4.2 RFC 7231.
Zobaczmy teraz, jak ta interakcja działa w oparciu o hipotetyczny protokół RPC na platformie AMQP:
- Strona A wysyła brokerowi wiadomości AMQP (nazywając go Messengerem) wiadomość zawierającą obraz i instrukcje, aby skierować go do Strony B w celu przetworzenia, a następnie odpowiedzieć stronie A z jakimś adresem dla obrazu
- Strona A czeka, prawdopodobnie robiąc inne rzeczy
- Messenger wysyła oryginalną wiadomość Strony A do Strony B.
- Strona B przetwarza wiadomość
- Strona B wysyła komunikatorowi wiadomość zawierającą adres przetworzonego obrazu i instrukcje, aby skierować tę wiadomość do strony A.
- Messenger wysyła stronie A wiadomość ze strony B zawierającą adres przetworzonego obrazu
- Strona A uważa swoją pracę za wykonaną, ponieważ ma teraz odniesienie do przetworzonego obrazu
- Kiedyś w przyszłości, gdy strona A potrzebuje obrazu, pobiera obraz za pomocą adresu (prawdopodobnie wysyłając wiadomości do innej osoby)
Czy widzisz tutaj problem? W obu przypadkach, Partia A nie może uzyskać adresu obrazu aż po Partia B przetwarza obraz . Jednak strona A nie potrzebuje obrazu od razu i, zgodnie z wszelkimi prawami, nie obchodzi go mniej, jeśli przetwarzanie zostanie zakończone!
Możemy to dość łatwo naprawić w przypadku AMQP, każąc Stronie B powiedzieć A, że B zaakceptował obraz do przetworzenia, podając A adres, pod którym będzie znajdować się obraz po zakończeniu przetwarzania. Następnie Strona B może wysłać A wiadomość w przyszłości, wskazującą, że przetwarzanie obrazu zostało zakończone. Wiadomości AMQP na ratunek!
Z wyjątkiem zgadnij, co: możesz osiągnąć to samo dzięki REST . W przykładzie AMQP zmieniliśmy komunikat „oto przetworzony obraz” na „obraz jest przetwarzany, możesz go zdobyć później”. Aby to zrobić w RESTful HTTP, użyjemy 202 Accepted
kodu i Content-Location
ponownie:
- Strona A wysyła
POST
wiadomość HTTP do Strony B za pomocąContent-Type: image/jpeg
- Strona B natychmiast odsyła
202 Accepted
odpowiedź, która zawiera rodzaj „operacji asynchronicznej”, która opisuje, czy przetwarzanie zostało zakończone i gdzie obraz będzie dostępny po zakończeniu przetwarzania. Uwzględniono również Content-Location: <link>
nagłówek, który w 202 Accepted
odpowiedzi stanowi łącze do zasobu reprezentowanego przez dowolny element odpowiedzi. W tym przypadku oznacza to, że jest to link do naszej operacji asynchronicznej!
- Strona A uważa swoją pracę za wykonaną, ponieważ ma teraz odniesienie do przetworzonego obrazu
- W przyszłości, gdy strona A potrzebuje przetworzonego obrazu, najpierw Pobiera zasób operacji asynchronicznej połączony z
Content-Location
nagłówkiem, aby ustalić, czy przetwarzanie zostało zakończone. Jeśli tak, Partia A następnie używa łącza w samej operacji asynchronicznej, aby uzyskać przetworzony obraz.
Jedyna różnica polega na tym, że w modelu AMQP strona B informuje stronę A, kiedy przetwarzanie obrazu jest zakończone. Ale w modelu REST strona A sprawdza, czy przetwarzanie jest wykonywane tuż przed faktycznym potrzebowaniem obrazu. Te podejścia są równoważnie skalowalne . W miarę powiększania się systemu liczba wiadomości wysyłanych zarówno w asynchronicznej strategii AMQP, jak i asynchronicznej strategii REST rośnie wraz z równoważną złożonością asymptotyczną. Jedyną różnicą jest to, że klient wysyła dodatkową wiadomość zamiast serwera.
Ale podejście REST ma jeszcze kilka sztuczek: dynamiczne wykrywanie i negocjowanie protokołu . Zastanów się, jak zaczęły się interakcje synchronizacji i asynchronizacji REST. Strona A wysłała dokładnie tę samą prośbę do Strony B, przy czym jedyną różnicą jest szczególny rodzaj komunikatu o sukcesie, na który Strona B odpowiedziała. Co jeśli Partia A chciałaby wybrać, czy przetwarzanie obrazu będzie synchroniczne czy asynchroniczne? Co się stanie, jeśli Partia A nie wie, czy Partia B może nawet przetwarzać asynchronicznie?
Cóż, HTTP faktycznie ma do tego już ustandaryzowany protokół! To się nazywa Preferencje HTTP, w szczególności respond-async
preferencja RFC 7240, sekcja 4.1. Jeśli strona A chce odpowiedzi asynchronicznej, zawiera Prefer: respond-async
nagłówek z początkowym żądaniem POST. Jeśli Strona B postanowi uszanować tę prośbę, odsyła 202 Accepted
odpowiedź zawierającą Preference-Applied: respond-async
. W przeciwnym razie Party B po prostu ignoruje Prefer
nagłówek i odsyła, 201 Created
jak zwykle.
Pozwala to Stronie A negocjować z serwerem, dynamicznie dostosowując się do dowolnej implementacji przetwarzania obrazu, z którą się rozmawia. Co więcej, użycie jawnych linków oznacza, że strona A nie musi wiedzieć o żadnych podmiotach innych niż B: brak brokera komunikatów AMQP, brak tajemniczej strony C, która wie, jak faktycznie przekształcić adres obrazu w dane obrazu, nie ma drugiej B-Async imprezuj, jeśli trzeba wysyłać żądania synchroniczne i asynchroniczne itp. Po prostu opisuje, czego potrzebuje, co opcjonalnie by chciał, a następnie reaguje na kody stanu, treść odpowiedzi i łącza. DodaćCache-Control
nagłówki w celu uzyskania wyraźnych instrukcji, kiedy zachować lokalne kopie danych, a teraz serwery mogą negocjować z klientami, których zasobów klienci mogą przechowywać lokalne (a nawet offline!) Kopie. W ten sposób budujesz luźno sprzężone odporne na uszkodzenia mikrousługi w REST.
UserCreated
zdarzenia (na przykład zduplikowana nazwa użytkownika lub wiadomość e-mail lub awaria bazy danych)./users/
punktu końcowego i pozwolić temu systemowi opublikować swoje zdarzenie, jeśli się powiedzie, i odpowiedzieć na żądanie nową jednostkąW przypadku systemu opartego na zdarzeniach asynchroniczne aspekty zwykle wchodzą w grę, gdy zmieni się coś, co reprezentuje stan, być może baza danych lub zagregowany widok niektórych danych. Korzystając z Twojego przykładu, wywołanie GET / api / users może po prostu zwrócić odpowiedź z usługi, która ma aktualną reprezentację listy użytkowników w systemie. W innym scenariuszu żądanie GET / api / users może spowodować, że usługa użyje strumienia zdarzeń od ostatniej migawki użytkowników, aby zbudować kolejną migawkę i po prostu zwrócić wyniki. System sterowany zdarzeniami niekoniecznie jest czysto asynchroniczny od żądania do odpowiedzi, ale zwykle znajduje się na poziomie, na którym usługi muszą wchodzić w interakcje z innymi usługami. Często nie ma sensu asynchroniczne zwracanie żądania GET, więc możesz po prostu zwrócić odpowiedź usługi,
źródło