Ripeti dopo di me:
Gli eventi REST e asincroni non sono alternative. Sono completamente ortogonali.
Puoi avere l'uno o l'altro, o entrambi, o nessuno dei due. Sono strumenti completamente diversi per domini problematici completamente diversi. In effetti, la comunicazione richiesta-risposta per scopi generici è assolutamente in grado di essere asincrona, guidata dagli eventi e tollerante ai guasti .
A titolo di esempio banale, il protocollo AMQP invia messaggi tramite una connessione TCP. In TCP, ogni pacchetto deve essere riconosciuto dal destinatario . Se un mittente di un pacchetto non riceve un ACK per quel pacchetto, continua a rinviare quel pacchetto fino a quando non viene ACK o fino a quando il livello dell'applicazione "si arrende" e abbandona la connessione. Si tratta chiaramente di un modello di richiesta-risposta non tollerante agli errori, poiché ogni "richiesta di invio di pacchetti" deve avere una "risposta di riconoscimento dei pacchetti" di accompagnamento e la mancata risposta comporta il fallimento dell'intera connessione. Tuttavia AMQP, un protocollo standardizzato e ampiamente adottato per la messaggistica asincrona con tolleranza agli errori, viene comunicato tramite TCP! Cosa dà?
Il concetto chiave qui in gioco è che i messaggi di tolleranza agli errori liberamente accoppiabili e scalabili sono definiti da quali messaggi si inviano , non da come li si invia . In altre parole, l' accoppiamento lento è definito a livello di applicazione .
Diamo un'occhiata a due parti che comunicano direttamente con RESTful HTTP o indirettamente con un broker di messaggi AMQP. Supponiamo che la Parte A desideri caricare un'immagine JPEG sulla Parte B che renderà più nitida, compressa o migliorata l'immagine. La parte A non necessita immediatamente dell'immagine elaborata, ma richiede un riferimento ad essa per un utilizzo e un recupero futuri. Ecco un modo che potrebbe andare in REST:
- La parte A invia un
POST
messaggio di richiesta HTTP alla parte B conContent-Type: image/jpeg
- La parte B elabora l'immagine (per molto tempo se è grande) mentre la parte A attende, possibilmente facendo altre cose
- La parte B invia un
201 Created
messaggio di risposta HTTP alla parte A con Content-Location: <url>
un'intestazione che si collega all'immagine elaborata
- La parte A considera il proprio lavoro svolto poiché ora ha un riferimento all'immagine elaborata
- In futuro, quando Partito A ha bisogno l'immagine elaborata, si ottiene utilizzando il link dal precedente
Content-Location
intestazione
Il 201 Created
codice di risposta dice a un client che non solo la sua richiesta ha avuto successo, ma ha anche creato una nuova risorsa. In una risposta 201, l' Content-Location
intestazione è un collegamento alla risorsa creata. Questo è specificato nelle sezioni 6.3.2 e 3.1.4.2 di RFC 7231.
Ora, vediamo come funziona questa interazione su un ipotetico protocollo RPC su AMQP:
- La parte A invia un broker di messaggi AMQP (chiamalo Messenger) un messaggio contenente l'immagine e le istruzioni per instradarlo alla parte B per l'elaborazione, quindi risponde alla parte A con un indirizzo di qualche tipo per l'immagine
- La parte A aspetta, forse facendo altre cose
- Messenger invia il messaggio originale della parte A alla parte B.
- La parte B elabora il messaggio
- La parte B invia a Messenger un messaggio contenente un indirizzo per l'immagine elaborata e le istruzioni per instradare quel messaggio alla parte A
- Messenger invia alla parte A il messaggio della parte B contenente l'indirizzo dell'immagine elaborata
- La parte A considera il proprio lavoro svolto poiché ora ha un riferimento all'immagine elaborata
- Qualche volta in futuro quando la Parte A ha bisogno dell'immagine, recupera l'immagine usando l'indirizzo (possibilmente inviando messaggi a un'altra parte)
Vedi il problema qui? In entrambi i casi, la parte A non può ottenere un indirizzo immagine fino a quando la parte B non elabora l'immagine . Tuttavia, la Parte A non ha bisogno immediatamente dell'immagine e, a tutti i diritti, non potrebbe importare di meno se l'elaborazione è ancora terminata!
Possiamo risolverlo abbastanza facilmente nel caso AMQP facendo in modo che Party B dica ad A che B ha accettato l'immagine per l'elaborazione, fornendo ad A un indirizzo per dove sarà l'immagine dopo che l'elaborazione è stata completata. Quindi la Parte B può inviare A un messaggio in futuro indicando che l'elaborazione dell'immagine è terminata. Messaggistica AMQP in soccorso!
Tranne indovinare cosa: puoi ottenere la stessa cosa con REST . Nell'esempio AMQP abbiamo cambiato il messaggio "ecco l'immagine elaborata" in un messaggio "l'immagine è in elaborazione, è possibile ottenerla in un secondo momento". Per farlo in HTTP RESTful, useremo il 202 Accepted
codice e di Content-Location
nuovo:
- La parte A invia un
POST
messaggio HTTP alla parte B conContent-Type: image/jpeg
- La parte B invia immediatamente una
202 Accepted
risposta che contiene una sorta di contenuto di "operazione asincrona" che descrive se l'elaborazione è terminata e dove l'immagine sarà disponibile al termine dell'elaborazione. È inclusa anche Content-Location: <link>
un'intestazione che, in una 202 Accepted
risposta, è un collegamento alla risorsa rappresentata da qualunque sia il corpo della risposta. In questo caso, ciò significa che è un collegamento alla nostra operazione asincrona!
- La parte A considera il proprio lavoro svolto poiché ora ha un riferimento all'immagine elaborata
- Qualche volta in futuro, quando la Parte A ha bisogno dell'immagine elaborata, prima ottiene la risorsa dell'operazione asincrona collegata
Content-Location
nell'intestazione per determinare se l'elaborazione è terminata. In tal caso, la Parte A utilizza quindi il collegamento nell'operazione asincrona stessa per OTTENERE l'immagine elaborata.
L'unica differenza qui è che nel modello AMQP, Party B dice a Party A quando l'elaborazione delle immagini è terminata. Ma nel modello REST, la Parte A verifica se l'elaborazione viene eseguita appena prima che abbia effettivamente bisogno dell'immagine. Questi approcci sono equivalentemente scalabili . Man mano che il sistema aumenta, il numero di messaggi inviati sia nelle strategie asincrone AMQP sia nelle strategie REST asincrone aumenta con una complessità asintotica equivalente. L'unica differenza è che il client sta inviando un messaggio aggiuntivo anziché il server.
Ma l'approccio REST ha qualche asso nella manica: scoperta dinamica e negoziazione del protocollo . Considera come sono iniziate le interazioni REST di sincronizzazione e asincrone. La parte A ha inviato la stessa identica richiesta alla parte B, con l'unica differenza che è il particolare tipo di messaggio di successo con cui la parte B ha risposto. Cosa succederebbe se la Parte A volesse scegliere se l'elaborazione delle immagini fosse sincrona o asincrona? Cosa succede se la Parte A non sa se la Parte B è anche in grado di elaborare in modo asincrono?
Bene, HTTP ha già un protocollo standardizzato per questo! Si chiama Preferenze HTTP, in particolare la respond-async
preferenza di RFC 7240 Sezione 4.1. Se la Parte A desidera una risposta asincrona, include Prefer: respond-async
un'intestazione con la sua richiesta POST iniziale. Se la Parte B decide di onorare questa richiesta, invia una 202 Accepted
risposta che include a Preference-Applied: respond-async
. Altrimenti, la Parte B ignora semplicemente l' Prefer
intestazione e rispedisce 201 Created
normalmente.
Ciò consente alla Parte A di negoziare con il server, adattandosi dinamicamente a qualsiasi implementazione di elaborazione delle immagini con cui sta parlando. Inoltre, l'uso di collegamenti espliciti significa che la Parte A non deve conoscere parti diverse da B: nessun broker di messaggi AMQP, nessuna misteriosa Parte C che sappia come trasformare effettivamente l'indirizzo dell'immagine in dati di immagine, nessun secondo B-Async parte se devono essere fatte richieste sia sincrone che asincrone, ecc. Descrive semplicemente ciò di cui ha bisogno, ciò che opzionalmente vorrebbe, e quindi reagisce a codici di stato, contenuto della risposta e collegamenti. AggiungereCache-Control
intestazioni per istruzioni esplicite su quando conservare copie locali dei dati, e ora i server possono negoziare con i clienti di quali risorse i clienti possono conservare copie locali (o anche offline!). Questo è il modo in cui si creano microservizi con tolleranza agli errori liberamente accoppiati in REST.