web-dev-qa-db-fra.com

ActiveMQ: comment gérer les basculements de courtier lors de l'utilisation de files d'attente temporaires

Sur mes applications JMS, nous utilisons des files d'attente temporaires sur les producteurs pour pouvoir recevoir des réponses des applications grand public.

Je suis confronté exactement au même problème de ma part, comme mentionné dans ce fil: http://activemq.2283324.n4.nabble.com/jira-Created-AMQ-3336-Temporary-Destination-errors-on-HA -failover-in-broker-network-with-Failover-tt-td3551034.html # a3612738

Chaque fois que je redémarrais un courtier arbitraire dans mon réseau, je recevais de nombreuses erreurs comme celle-ci dans mon journal d'application consommateur en essayant d'envoyer une réponse à une file d'attente temporaire:

javax.jms.InvalidDestinationException:
  Cannot publish to a deleted Destination: temp-queue://ID:...

Ensuite, j'ai vu la réponse de Gary là-bas suggérant d'utiliser

jms.watchTopicAdvisories=false

comme paramètre d'URL sur le client brokerURL. J'ai rapidement modifié les URL de mon courtier client avec ce paramètre supplémentaire. Cependant, je vois maintenant des erreurs comme celle-ci lorsque je redémarre mes courtiers en réseau pour ce test de basculement:

javax.jms.JMSException: 
  The destination temp-queue:
    //ID:client.Host-65070-1308610734958-2:1:1 does not exist.

J'utilise la version ActiveMQ 5.5. Et mon URL de courtier client ressemble à ceci:

failover:(tcp://amq-Host1:61616,tcp://amq-Host2.tred.aol.com:61616,tcp://amq-Host3:61616,tcp://amq-Host4:61616)?jms.useAsyncSend=true&timeout=5000&jms.watchTopicAdvisories=false

De plus, voici mon XML de configuration activemq pour l'un des 4 courtiers: amq1.xml

Quelqu'un ici peut-il examiner ce problème et me suggérer l'erreur que je fais dans cette configuration.

Mettre à jour:

Pour clarifier davantage la façon dont je fais la demande-réponse dans mon code:

  1. J'utilise déjà une destination par producteur (c'est-à-dire une file d'attente temporaire) et je l'ai définie dans l'en-tête de réponse de chaque message.
  2. J'envoie déjà un identifiant de corrélation unique par message dans l'en-tête JMSCorrelationID.
  3. Pour autant que je sache, même Camel et Spring utilisent également une file d'attente temporaire pour le mécanisme de demande-réponse. La seule différence est que l'implémentation Spring JMS crée et détruit la file d'attente temporaire pour chaque message tandis que je crée une file d'attente temporaire pour la durée de vie du producteur. Cette file d'attente temporaire est détruite lors de l'arrêt de l'application client (producteur) ou par le courtier AMQ lorsqu'il se rend compte qu'aucun producteur actif n'est associé à cette file d'attente temporaire.
  4. Je fixe déjà une expiration de message sur chaque message côté producteur afin que le message ne soit pas maintenu dans une file d'attente trop longtemps (60 sec).
52
anubhava

Il existe un attribut de courtier, org.Apache.activemq.broker.BrokerService # cacheTempDestinations qui devrait aider au basculement: cas. Définissez-le sur true dans la configuration xml et une destination temporaire ne sera pas supprimée immédiatement lorsqu'un client se déconnecte. Un basculement rapide: la reconnexion pourra à nouveau produire et/ou consommer à partir de la file d'attente temporaire.

Il existe une tâche de temporisation basée sur timeBeforePurgeTempDestinations (5 secondes par défaut) qui gère la suppression du cache.

Une mise en garde cependant, je ne vois aucun test dans activemq-core qui utilise cet attribut, donc je ne peux vous donner aucune garantie sur celui-ci.

25
gtully

Des files d'attente temporaires sont créées sur le courtier auquel le demandeur (producteur) dans votre scénario de demande-réponse se connecte. Ils sont créés à partir d'un javax.jms.Session, ainsi de suite lors de la déconnexion de la session, que ce soit en raison de la déconnexion du client ou de l'échec/du basculement du courtier, ces files d'attente ont définitivement disparu. Aucun des autres courtiers ne comprendra ce que l'on entend lorsqu'un de vos consommateurs tente de répondre à ces files d'attente; d'où votre exception.

Cela nécessite un changement d'architecture dans l'état d'esprit en supposant que vous souhaitez gérer le basculement et conserver tous vos messages. Voici une manière générale d'attaquer le problème:

  1. Vos en-têtes de réponse doivent faire référence à une file d'attente spécifique au processus demandeur: par ex. queue:response.<client id>. L'ID client peut être un nom standard si vous avez un nombre limité de clients ou un UUID si vous en avez un grand nombre.
  2. Le message sortant doit définir un identificateur de corrélation (simplement une piqûre qui vous permet d'associer une demande à une réponse - après tout, les demandeurs peuvent faire plus d'une demande en même temps). Il est défini dans l'en-tête JMSCorrelationID et doit être copié de la demande dans le message de réponse.
  3. Le demandeur doit configurer un écouteur dans cette file d'attente qui renverra le corps du message au thread demandeur en fonction de cet identifiant de corrélation. Il y a du code multithreading qui doit être écrit pour cela, car vous devrez gérer manuellement quelque chose comme une carte d'ID de corrélation avec les threads d'origine (via Futures peut-être).

Il s'agit d'une approche similaire à celle adoptée par Apache Camel pour requête-réponse via messagerie .

Une chose à garder à l'esprit est que la file d'attente ne disparaîtra pas lorsque le client le fera, vous devez donc définir une durée de vie sur le message de réponse de sorte qu'il soit supprimé du courtier s'il n'a pas été consommé, sinon vous obtiendrez un arriéré de messages non consommés. Vous devrez également configurer une stratégie de file d'attente de lettres mortes pour éliminer automatiquement les messages expirés .

9
Jakub Korab