Повторюйте за мною:
REST та асинхронні події не є альтернативою. Вони повністю ортогональні.
Ви можете мати одне, або друге, або те, і інше. Вони абсолютно різні інструменти для абсолютно різних проблемних областей. Насправді комунікація загального призначення на запит-відповідь абсолютно здатна бути асинхронною, керованою подіями та відмовою .
Як тривіальний приклад, протокол AMQP передає повідомлення через TCP-з'єднання. У TCP кожен одержувач повинен підтверджувати кожен пакет . Якщо відправник пакету не отримує ACK для цього пакету, він продовжує повторно відправляти цей пакет, поки він не стане ACK'd або поки рівень програми "не здасться" і не припинить з'єднання. Це, очевидно, невідмовна модель запиту-відповіді, тому що кожен "запит на відправку пакета" повинен мати супровідну "відповідь підтвердження пакетів", а невідповідь призводить до відмови всього з’єднання. Але AMQP, стандартизований і широко прийнятий протокол для асинхронних помилок, що мають толерантність, передається через TCP! Що дає?
Основна концепція, яка тут грає, полягає в тому, що масштабоване слабко пов'язане з відмовою стійке обмін повідомленнями визначається тим, які повідомлення ви надсилаєте , а не тим, яким чином ви їх надсилаєте . Іншими словами, нещільне з'єднання визначається на рівні застосування .
Давайте розглянемо дві сторони, що спілкуються безпосередньо з RESTful HTTP або опосередковано з брокером повідомлень AMQP. Припустимо, сторона A бажає завантажити зображення JPEG на Party B, який буде різко, стискати або іншим чином покращувати зображення. Партія A не потребує опрацьованого зображення відразу, але для подальшого використання та пошуку потрібна посилання на нього. Ось один із способів, який може пройти в REST:
- Сторона A надсилає повідомлення із
POST
запитом HTTP до Party B зContent-Type: image/jpeg
- Партія B обробляє зображення (тривалий час, якщо воно велике), поки Партія А чекає, можливо, робить інші речі
- Сторона B надсилає повідомлення
201 Created
відповіді HTTP на Party A із Content-Location: <url>
заголовком, який посилається на оброблюване зображення
- Партія А вважає її виконаною роботою, оскільки тепер має посилання на оброблюваний образ
- Коли-небудь у майбутньому, коли партії A потрібен оброблений образ, він отримує його за допомогою посилання з попереднього
Content-Location
заголовка
Код 201 Created
відповіді повідомляє клієнту, що їх запит не тільки був успішним, він також створив новий ресурс. У відповіді 201 Content-Location
заголовок - це посилання на створений ресурс. Це визначено у розділах 6.3.2 та 3.1.4.2 RFC 7231.
Тепер давайте подивимося, як ця взаємодія працює над гіпотетичним протоколом RPC поверх AMQP:
- Party A надсилає брокеру повідомлення AMQP (називайте його Messenger) повідомлення, що містить зображення та вказівки, щоб направити його на Party B для обробки, а потім відповісти на Party A з якоюсь адресою для зображення
- Партія А чекає, можливо, роблячи інші речі
- Месенджер надсилає оригінальне повідомлення учасниці А учасниці B
- Партія B обробляє повідомлення
- Сторона B надсилає Месенджеру повідомлення, що містить адресу обробленого зображення та вказівки для маршрутизації цього повідомлення до Party A
- Месенджер надсилає стороні А повідомлення від учасника B, що містить оброблювану адресу зображення
- Партія А вважає її виконаною роботою, оскільки тепер має посилання на оброблюваний образ
- Коли-небудь у майбутньому, коли учаснику A потрібне зображення, він отримує зображення за адресою (можливо, надсилаючи повідомлення іншій стороні)
Ви бачите тут проблему? В обох випадках, Сторона А не може отримати адресу зображення , поки після того, як Сторона B обробляє зображення . Втім, учаснику А зображення не потрібно відразу, і, за всіма правами, не могло б менше хвилюватись, якщо обробка ще закінчена!
Ми можемо це легко виправити у випадку AMQP, якщо сторона B скаже A, що B прийняла зображення на обробку, давши A адресу, де буде зображення після завершення обробки. Тоді учасник B може надіслати повідомлення десь у майбутньому із зазначенням, що обробка зображення закінчена. AMQP-повідомлення на допомогу!
За винятком здогадайтесь, що: ви можете досягти того ж, що і з REST . У прикладі AMQP ми змінили повідомлення "ось оброблене зображення" на повідомлення "зображення обробляється, ви можете отримати його пізніше". Для цього в RESTful HTTP ми знову використаємо 202 Accepted
код Content-Location
:
- Сторона A надсилає повідомлення HTTP
POST
до Party B зContent-Type: image/jpeg
- Сторона B негайно надсилає
202 Accepted
відповідь, що містить якийсь вміст "асинхронної операції", який описує, чи завершена обробка та де зображення буде доступне, коли буде виконано обробку. Також включений Content-Location: <link>
заголовок, який у 202 Accepted
відповіді є посиланням на ресурс, представлений будь-яким органом відповіді. У цьому випадку це означає, що це посилання на нашу асинхронну операцію!
- Партія А вважає її виконаною роботою, оскільки тепер має посилання на оброблюваний образ
- Коли-небудь у майбутньому, коли партії A потрібен оброблений образ, він спочатку отримує ресурс операції асинхронізації, пов'язаний у
Content-Location
заголовку, щоб визначити, чи завершена обробка. Якщо так, то сторона A використовує посилання в самій операції async для отримання обробленого зображення.
Єдина відмінність тут полягає в тому, що в моделі AMQP партія B повідомляє партії A, коли буде виконана обробка зображення. Але в моделі REST партія A перевіряє, чи обробка проводиться безпосередньо перед тим, як вона насправді потребує зображення. Ці підходи в рівній мірі масштабовані . Коли система зростає, кількість повідомлень, що надсилаються як в асинхронній AMQP, так і в асинхронній стратегії REST, збільшується з еквівалентною асимптотичною складністю. Єдина відмінність - клієнт надсилає додаткове повідомлення замість сервера.
Але підхід REST має ще кілька хитрощів в руці: динамічне виявлення та узгодження протоколу . Поміркуйте, як почалися взаємодії синхронізації та асинхронізації REST. Партія А надіслала такий самий запит до Партії Б, з тією лише різницею, що саме той вид повідомлення про успіх, на який відповіла Партія В. Що робити, якщо учасник A хотів вибрати, чи обробка зображення буде синхронною чи асинхронною? Що робити, якщо сторона А не знає, чи може партія B навіть здатна асинхронізувати обробку?
Ну, HTTP насправді вже має стандартизований протокол для цього! Вона називається HTTP Preferences, зокрема respond-async
перевагою RFC 7240 Розділ 4.1. Якщо сторона A бажає асинхронної відповіді, вона включає Prefer: respond-async
заголовок із початковим запитом POST. Якщо Сторона Б вирішує виконати цей запит, він відправляє назад 202 Accepted
відповідь , який включає в себе Preference-Applied: respond-async
. В іншому випадку Party B просто ігнорує Prefer
заголовок і відсилає назад, 201 Created
як це було б зазвичай.
Це дозволяє учаснику A вести переговори з сервером, динамічно адаптуючись до того, з якою реалізацією обробки зображень ви не розмовляєте. Крім того, використання явних посилань означає, що сторона A не повинна знати про будь-яку сторону, окрім B: ні брокер повідомлень AMQP, ні таємнича сторона C, яка знає, як насправді перетворити адресу зображення в дані зображення, немає другого B-Async учасника, якщо потрібно робити як синхронні, так і асинхронні запити і т. д. Він просто описує те, що йому потрібно, що б це не хотілося, а потім реагує на коди стану, вміст відповідей та посилання. Додати доCache-Control
заголовки для чітких інструкцій щодо збереження локальних копій даних, і тепер сервери можуть домовлятися з клієнтами, які ресурси клієнти можуть зберігати локальні (або навіть офлайн!) копії. Ось так ви створюєте в REST мікроспоруди з низькою сполученою відмовою.