web-dev-qa-db-fra.com

Demande-réponse synchrone simultanée avec JMS/ActiveMQ - Modèles/Bibliothèques?

J'ai une application Web sur laquelle, lorsque l'utilisateur envoie une demande, nous envoyons un message JMS à un service distant, puis attendons la réponse. (Il y a aussi des requêtes asynchrones, et nous avons différentes finesses configurées pour la relecture des messages, etc., nous préférerions donc rester avec JMS au lieu de, par exemple, HTTP)

Dans Comment implémenter la réponse à la demande avec JMS? , ActiveMQ semble décourager l’idée de files d’attente temporaires par requête ou de consommateurs temporaires avec sélecteurs sur JMSCorrelationID, en raison de la surcharge liée à leur rotation.

Toutefois, si j'utilise des consommateurs en pool pour les réponses, comment puis-je renvoyer du consommateur de réponse vers le thread demandeur original?

Je pourrais certainement écrire mon propre enregistrement/envoi de rappel sécurisé par les threads, mais je déteste écrire du code dont je soupçonne qu'il a déjà été écrit par quelqu'un qui en sait plus que moi.

Cette page ActiveMQ recommande Lingo , qui n’a pas été mis à jour depuis 2006, et Camel Spring Remoting , qui a été banni par mon équipe pour ses nombreux bugs.

Existe-t-il une meilleure solution, sous la forme d'une bibliothèque implémentant ce modèle ou sous la forme d'un modèle différent permettant de simuler une requête-réponse synchrone via JMS?


Question connexe SO:

23
joshwa

Un collègue a suggéré une solution potentielle: une file d'attente de réponses/consommateur par thread Webapp, et nous pouvons définir l'adresse de retour sur la file d'attente de réponses appartenant à ce thread particulier. Étant donné que ces threads ont généralement une longue durée de vie (et sont réutilisés pour les requêtes Web ultérieures), nous ne devons subir que des frais supplémentaires au moment où le thread génère le thread.

Cela dit, tout cet exercice me fait repenser JMS par rapport à HTTP ... :)

3
joshwa

Dans un projet précédent, nous avions une situation similaire, où une demande de synchronisation WS était gérée avec une paire de messages JMS Async req/res. Nous utilisions à l’époque Jboss JMS impl et la variable destinations temporaire entraînant de gros frais généraux.

Nous avons fini par écrire un répartiteur sécurisé pour les threads, laissant le WS attendre jusqu'à ce que la réponse JMS soit reçue. Nous avons utilisé le CorrelationID pour associer la réponse à la demande.

Cette solution a été conçue en interne, mais je suis tombé sur une implémentation de la carte de Nice qui résout le problème de l’adéquation d’une réponse à une demande.

BlockingMap

Si votre solution est en cluster, vous devez veiller à ce que les messages de réponse soient envoyés au bon nœud du cluster. Je ne connais pas ActiveMQ, mais je me souviens que la messagerie JBoss avait quelques problèmes sous le capot pour leurs destinations pouvant être clusterisées.

4
maasg

Je pensais toujours à utiliser Camel et le laisser gérer le filetage, peut-être sans ressort-remoting mais uniquement avec des ProducerTemplates bruts.

Camel a de la documentation intéressante sur le sujet et fonctionne très bien avec ActiveMQ. http://camel.Apache.org/jms#JMS-RequestreplyoverJMS

Pour ce qui est de votre question sur la création d’un consommateur basé sur un sélecteur et de la surcharge, la documentation ActiveMQ indique qu’elle nécessite un aller-retour vers le courtier ActiveMQ, qui peut se trouver de l’autre côté du globe ou sur un réseau à délai élevé. La surcharge dans ce cas est le temps de transmission aller-retour TCP/IP vers le courtier AMQ. Je considérerais cela comme une option. Je l'ai utilisé plusieurs fois avec succès.

4
Petter Nordlander

C'est un vieil, mais j'ai atterri ici à la recherche de quelque chose d'autre et j'ai vraiment quelques idées (j'espère que cela sera utile à quelqu'un).

Nous avons mis en place un cas d'utilisation très similaire, Hazelcast étant notre châssis pour la communication entre les nœuds du cluster. L'essentiel est constitué de 2 jeux de données: 1 carte distribuée pour les réponses, 1 liste «locale» d'attendeurs de réponses (sur chaque nœud du cluster).

  • chaque demande (recevant son propre thread de Jetty) crée une entrée dans la carte des serveurs locaux; l'entrée a évidemment la corrélation UID et un objet qui servira de sémaphore
  • la requête est ensuite envoyée au serveur distant (REST/JMS) et le thread d'origine commence à attendre le sémaphore; UID doit faire partie de la requête
  • remote renvoie la réponse et l'écrit dans la mappe de réponses avec l'UID corrélé
  • la carte des réponses est en cours d'écoute; si l'UID de la réponse qui arrive est trouvé dans la carte des demandeurs locaux, son sémaphore est notifié, le fil de la requête d'origine est publié, récupérant la réponse dans la carte de réponses et la renvoyant au client.

Ceci est une description générale, je peux mettre à jour une réponse avec quelques optimisations, au cas où cela susciterait un intérêt quelconque.

0
GullerYA

J'ai toujours utilisé CorrelationID pour les requêtes/réponses et je n'ai jamais eu de problèmes de performances. Je ne peux pas imaginer pourquoi cela constituerait un problème de performances. Les systèmes de messagerie devraient être très rapides à mettre en œuvre et constitueraient une fonctionnalité très importante à bien mettre en œuvre.

http://www.eaipatterns.com/RequestReplyJmsExample.html a les solutions de flux de remorquage principales utilisant replyToQueue ou correlationID.

0
ams