web-dev-qa-db-de.com

Gleichzeitige synchrone Request-Reply mit JMS/ActiveMQ - Patterns/Libraries?

Ich habe eine Web-App, in der wir, wenn der Benutzer eine Anfrage sendet, eine JMS-Nachricht an einen Remote-Service senden und dann auf die Antwort warten. (Es gibt auch asynchrone Anfragen, und wir haben verschiedene Einstellungen für die Nachrichtenwiedergabe usw., daher möchten wir uns lieber an JMS als an HTTP halten.)

In Wie sollte ich die Anforderungsantwort mit JMS implementieren? , ActiveMQ scheint die Idee von temporären Warteschlangen pro Anforderung oder temporären Konsumenten mit Selektoren für die JMSCorrelationID zu entmutigen, da sie mit einem Mehraufwand beim Hochfahren verbunden sind.

Wie kann ich jedoch, wenn ich gepoolte Verbraucher für die Antworten verwende, vom Antwortverbraucher zurück zum ursprünglichen anfragenden Thread senden?

Ich könnte sicherlich meine eigene thread-sichere Rückrufregistrierung versendung schreiben, aber ich hasse es, Code zu schreiben, von dem ich vermute, dass er bereits von jemandem geschrieben wurde, der es besser weiß als ich.

Diese ActiveMQ-Seite empfiehlt/- Lingo , das seit 2006 nicht mehr aktualisiert wurde, und Camel Spring Remoting , das von meinem Team wegen seiner vielen Gotcha-Bugs für die Hölle gesperrt wurde.

Gibt es eine bessere Lösung in Form einer Bibliothek, die dieses Muster implementiert, oder in Form eines anderen Musters zur Simulation der synchronen Anfrage-Antwort über JMS?


Verwandte SO Frage:

23
joshwa

Ein Kollege schlug eine mögliche Lösung vor: Eine Antwortwarteschlange/ein Verbraucher pro Webanwendungsthread, und wir können die Rücksprungadresse auf die Antwortwarteschlange festlegen, die diesem bestimmten Thread gehört. Da diese Threads in der Regel langlebig sind (und für nachfolgende Webanforderungen wiederverwendet werden), müssen wir nur den Overhead erleiden, wenn der Thread vom Pool erzeugt wird.

Das heißt, diese ganze Übung bringt mich dazu, JMS vs HTTP zu überdenken ... :)

3
joshwa

In einem früheren Projekt hatten wir eine ähnliche Situation, in der eine Synchronisierungs-WS-Anforderung mit einem Paar von JMS-Nachrichten mit asynchroner Anforderung/Auflösung verarbeitet wurde. Zu dieser Zeit verwendeten wir das JBoss-JMS-Impl und temporäre destinations, bei denen ein großer Overhead anfiel.

Am Ende haben wir einen thread-sicheren Dispatcher geschrieben und den WS warten lassen, bis die JMS-Antwort eingeht. Mit der CorrelationID haben wir die Antwort wieder der Anforderung zugeordnet.

Diese Lösung war allesamt einheimisch, aber ich bin auf ein Nizza-Blockier-Map-Gerät gestoßen, das das Problem löst, eine Antwort auf eine Anfrage abzugleichen.

BlockingMap

Wenn Ihre Lösung in einem Cluster vorliegt, müssen Sie darauf achten, dass die Antwortnachrichten an den richtigen Knoten im Cluster gesendet werden. Ich kenne ActiveMQ nicht, aber ich erinnere mich, dass JBoss Messaging einige Probleme mit ihren clusterfähigen Zielen hatte.

4
maasg

Ich würde immer noch darüber nachdenken, Camel zu verwenden und es das Einfädeln überlassen, vielleicht ohne Federentfernung, aber nur rohe ProducerTemplates.

Camel hat einige nette Dokumentationen zu diesem Thema und funktioniert sehr gut mit ActiveMQ. http://camel.Apache.org/jms#JMS-RequestreplyoverJMS

In den ActiveMQ-Dokumenten wird für Ihre Frage zum Hochfahren eines selektorbasierten Verbrauchers und zum Overhead angegeben, dass ein Roundtrip zum ActiveMQ-Broker erforderlich ist, der sich möglicherweise auf der anderen Seite des Globus oder in einem Netzwerk mit hoher Verzögerung befindet. Der Aufwand in diesem Fall ist die TCP/IP-Umlaufzeit zum AMQ-Broker. Ich würde dies als Option betrachten. Habe es mehrfach mit Erfolg benutzt.

4

Es ist alt, aber ich bin auf der Suche nach etwas anderem gelandet und habe tatsächlich einige Einsichten (hoffentlich hilft es jemandem).

Wir haben einen sehr ähnlichen Anwendungsfall implementiert, bei dem Hazelcast unser Chassis für die Cluster-Internode-Kommunikation ist. Das Wesentliche sind 2 Datensätze: 1 verteilte Karte für Antworten, 1 "lokale" Liste der Antwortwartenden (auf jedem Knoten im Cluster).

  • jede Anfrage (die einen eigenen Thread von Jetty erhält) erstellt einen Eintrag in der Karte der lokalen Kellner. Der Eintrag hat offensichtlich die Korrelations-UID und ein Objekt, das als Semaphor dient
  • dann wird die Anforderung an die entfernte Station (REST/JMS) gesendet und der ursprüngliche Thread beginnt auf dem Semaphor zu warten. Die UID muss Teil der Anforderung sein
  • remote gibt die Antwort zurück und schreibt sie mit der entsprechenden UID in die Antwortzuordnung
  • antwortkarte wird abgehört; Wenn die UID der neu eingehenden Antwort in der Karte der lokalen Kellner gefunden wird, wird das Semaphor benachrichtigt, der Thread der ursprünglichen Anforderung wird freigegeben, und die Antwort wird aus der Antwortkarte abgerufen und an den Client zurückgesendet

Dies ist eine allgemeine Beschreibung. Ich kann eine Antwort mit einigen Optimierungen aktualisieren, falls Interesse besteht.

0
GullerYA

Ich habe CorrelationID immer für die Anforderung/Antwort verwendet und hatte nie Leistungsprobleme. Ich kann mir nicht vorstellen, warum das überhaupt ein Leistungsproblem sein sollte. Es sollte für jedes Messagingsystem sehr schnell zu implementieren sein und eine ziemlich wichtige Funktion, die gut zu implementieren ist.

http://www.eaipatterns.com/RequestReplyJmsExample.html verwendet die beiden Hauptstromlösungen replyToQueue oder correlationID.

0
ams