Sprich mir nach:
REST- und asynchrone Ereignisse sind keine Alternativen. Sie sind völlig orthogonal.
Sie können die eine oder die andere oder beide oder keine haben. Sie sind völlig unterschiedliche Werkzeuge für völlig unterschiedliche Problembereiche. Tatsächlich kann die allgemeine Anfrage-Antwort-Kommunikation absolut asynchron, ereignisgesteuert und fehlertolerant sein .
Als einfaches Beispiel sendet das AMQP-Protokoll Nachrichten über eine TCP-Verbindung. In TCP muss jedes Paket vom Empfänger bestätigt werden . Wenn ein Absender eines Pakets keine Bestätigung für dieses Paket erhält, sendet er das Paket so lange erneut, bis es bestätigt wurde oder bis die Anwendungsebene "aufgibt" und die Verbindung aufgibt. Dies ist eindeutig ein nicht fehlertolerantes Anforderungs-Antwort-Modell, da jede "Paketsendeanforderung" eine begleitende "Paketbestätigungsantwort muss , und führt dazu, dass die gesamte Verbindung fehlschlägt. Dennoch wird AMQP, ein standardisiertes und weit verbreitetes Protokoll für asynchrones fehlertolerantes Messaging, über TCP kommuniziert! Was gibt?
Das Kernkonzept hierbei ist, dass skalierbares, lose gekoppeltes, fehlertolerantes Messaging durch die von Ihnen gesendeten Nachrichten definiert wird , nicht durch die Art und Weise , wie Sie sie senden . Mit anderen Worten, lose Kopplung auf der Anwendungsschicht definiert .
Betrachten wir zwei Parteien, die entweder direkt mit RESTful HTTP oder indirekt mit einem AMQP-Nachrichtenbroker kommunizieren. Angenommen, Party A möchte ein JPEG-Bild zu Party B hochladen, um das Bild zu schärfen, zu komprimieren oder auf andere Weise zu verbessern. Partei A benötigt das verarbeitete Bild nicht sofort, sondern benötigt einen Verweis darauf für die zukünftige Verwendung und den späteren Abruf. Hier ist ein Weg, der in REST gehen könnte:
- Teilnehmer A sendet ein HTTP
POST
Anforderungsnachricht an Teilnehmer B mitContent-Type: image/jpeg
- Partei B verarbeitet das Bild (für eine lange Zeit, wenn es groß ist), während Partei A wartet und möglicherweise andere Dinge tut
- Teilnehmer B sendet eine HTTP-
201 Created
Antwortnachricht an Teilnehmer A mit einem Content-Location: <url>
Header, der auf das verarbeitete Bild verweist
- Partei A betrachtet ihre Arbeit als erledigt, da sie nun einen Verweis auf das verarbeitete Bild hat
- Irgendwann in der Zukunft, wenn Partei A das verarbeitete Bild benötigt, wird es unter Verwendung des Links aus dem früheren
Content-Location
Header abgerufen
Der 201 Created
Antwortcode teilt einem Client mit, dass die Anforderung nicht nur erfolgreich war, sondern dass auch eine neue Ressource erstellt wurde. In einer 201-Antwort ist der Content-Location
Header eine Verknüpfung zur erstellten Ressource. Dies ist in RFC 7231, Abschnitte 6.3.2 und 3.1.4.2 angegeben.
Lassen Sie uns nun sehen, wie diese Interaktion über ein hypothetisches RPC-Protokoll auf AMQP funktioniert:
- Teilnehmer A sendet an einen AMQP-Nachrichtenbroker ("Messenger") eine Nachricht mit dem Bild und Anweisungen, um es zur Verarbeitung an Teilnehmer B weiterzuleiten, und antwortet dann Teilnehmer A mit einer Adresse für das Bild
- Party A wartet und macht möglicherweise andere Dinge
- Der Messenger sendet die ursprüngliche Nachricht von Party A an Party B
- Teilnehmer B verarbeitet die Nachricht
- Teilnehmer B sendet Messenger eine Nachricht mit einer Adresse für das verarbeitete Bild und Anweisungen zum Weiterleiten dieser Nachricht an Teilnehmer A
- Messenger sendet Party A die Nachricht von Party B mit der verarbeiteten Bildadresse
- Partei A betrachtet ihre Arbeit als erledigt, da sie nun einen Verweis auf das verarbeitete Bild hat
- Irgendwann in der Zukunft, wenn Partei A das Bild benötigt, ruft sie das Bild unter Verwendung der Adresse ab (möglicherweise durch Senden von Nachrichten an eine andere Partei).
Sehen Sie das Problem hier? In beiden Fällen kann Partei A eine Bildadresse erst abrufen, nachdem Partei B das Bild verarbeitet hat . Party A braucht das Bild jedoch nicht sofort und es ist ihm auch egal, ob die Verarbeitung noch abgeschlossen ist!
Wir können dieses Problem beheben , ziemlich leicht in dem AMQP Fall , indem Partei B A sagt , dass B akzeptierte das Bild für die Verarbeitung, so dass A eine Adresse für , wo das Bild wird nach der Verarbeitung wird beendet. Dann kann Teilnehmer B A irgendwann in der Zukunft eine Nachricht senden, die angibt, dass die Bildverarbeitung abgeschlossen ist. AMQP-Nachrichten zur Rettung!
Nur raten Sie mal: Mit REST können Sie dasselbe erreichen . Im AMQP-Beispiel wurde die Nachricht "Hier ist das verarbeitete Bild" in die Nachricht "Das Bild wird verarbeitet, Sie können es später abrufen" geändert. Um dies in RESTful HTTP zu tun, verwenden wir den 202 Accepted
Code und noch Content-Location
einmal:
- Teilnehmer A sendet eine HTTP-
POST
Nachricht an Teilnehmer B mitContent-Type: image/jpeg
- Teilnehmer B sendet sofort eine
202 Accepted
Antwort zurück, die eine Art Inhalt für "asynchrone Operationen" enthält, der beschreibt, ob die Verarbeitung abgeschlossen ist und wo das Bild verfügbar ist, wenn die Verarbeitung abgeschlossen ist. Ebenfalls enthalten ist ein Content-Location: <link>
Header, der in einer 202 Accepted
Antwort eine Verknüpfung zu der Ressource darstellt, die von dem jeweiligen Antworttext dargestellt wird. In diesem Fall ist dies eine Verknüpfung zu unserem asynchronen Betrieb!
- Partei A betrachtet ihre Arbeit als erledigt, da sie nun einen Verweis auf das verarbeitete Bild hat
- Irgendwann in der Zukunft, wenn Teilnehmer A das verarbeitete Abbild benötigt, ruft er zuerst die im
Content-Location
Header verknüpfte asynchrone Operationsressource ab, um festzustellen, ob die Verarbeitung abgeschlossen ist. Wenn dies der Fall ist, verwendet Teilnehmer A die Verknüpfung in der asynchronen Operation selbst, um das verarbeitete Bild abzurufen.
Der einzige Unterschied besteht darin, dass im AMQP-Modell Party B Party A mitteilt, wann die Bildverarbeitung abgeschlossen ist. Im REST-Modell prüft Partei A jedoch, ob die Verarbeitung unmittelbar vor dem tatsächlichen Bedarf des Abbilds erfolgt. Diese Ansätze sind äquivalent skalierbar . Wenn das System größer wird, nimmt die Anzahl der Nachrichten, die sowohl in der asynchronen AMQP- als auch in der asynchronen REST-Strategie gesendet werden, mit der entsprechenden asymptotischen Komplexität zu. Der einzige Unterschied besteht darin, dass der Client anstelle des Servers eine zusätzliche Nachricht sendet.
Der REST-Ansatz bietet jedoch noch einige weitere Tricks: Dynamische Erkennung und Protokollaushandlung . Überlegen Sie, wie sowohl die Synchronisierungs- als auch die asynchrone REST-Interaktion gestartet wurden. Partei A schickte genau die gleiche Anfrage an Partei B, mit dem einzigen Unterschied, dass Partei B auf die jeweilige Art der Erfolgsmeldung geantwortet hatte. Was wäre, wenn Teilnehmer A wählen wollte , ob die Bildverarbeitung synchron oder asynchron ist? Was ist, wenn Teilnehmer A nicht weiß, ob Teilnehmer B überhaupt eine asynchrone Verarbeitung ausführen kann?
Nun, HTTP hat tatsächlich bereits ein standardisiertes Protokoll dafür! Es nennt sich HTTP Preferences, speziell die respond-async
Voreinstellung von RFC 7240, Abschnitt 4.1. Wenn Teilnehmer A eine asynchrone Antwort wünscht, enthält er einen Prefer: respond-async
Header mit seiner anfänglichen POST-Anforderung. Wenn Partei B beschließt, dieser Bitte nachzukommen, sendet sie eine 202 Accepted
Antwort zurück, die a enthält Preference-Applied: respond-async
. Andernfalls ignoriert Party B den Prefer
Header einfach und sendet ihn 201 Created
wie gewohnt zurück .
Auf diese Weise kann Teilnehmer A mit dem Server verhandeln und sich dynamisch an die Implementierung der Bildverarbeitung anpassen, mit der er gerade spricht. Darüber hinaus bedeutet die Verwendung expliziter Links, dass Teilnehmer A nichts anderes als Teilnehmer B wissen muss: kein AMQP-Nachrichtenbroker, kein mysteriöser Teilnehmer C, der weiß, wie die Bildadresse tatsächlich in Bilddaten umgewandelt wird, kein zweiter B-Async Teilnehmer, wenn sowohl synchrone als auch asynchrone Anforderungen gestellt werden müssen usw. Es wird lediglich beschrieben, was benötigt wird, was optional gewünscht wird, und anschließend auf Statuscodes, Antwortinhalte und Links reagiert. HinzufügenCache-Control
Header mit expliziten Anweisungen zum Aufbewahren lokaler Kopien von Daten. Jetzt können Server mit Clients aushandeln, von welchen Ressourcen Clients lokale (oder sogar Offline-!) Kopien aufbewahren. Auf diese Weise erstellen Sie lose gekoppelte fehlertolerante Mikrodienste in REST.