Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveMQ: How to handle broker failovers while using temporary queues

On my JMS applications we use temporary queues on Producers to be able to receive replies back from Consumer applications.

I am facing exactly same issue on my end as mentioned in this thread: http://activemq.2283324.n4.nabble.com/jira-Created-AMQ-3336-Temporary-Destination-errors-on-H-A-failover-in-broker-network-with-Failover-tt-td3551034.html#a3612738

Whenever I restarted an arbitrary broker in my network, I was getting many errors like this in my Consumer application log while trying to send reply to a temporary queue:

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

Then I saw Gary's response there suggesting to use

jms.watchTopicAdvisories=false 

as a url param on the client brokerURL. I promptly changed my client broker URLs with this additional parameter. However now I am seeing errors like this when I restart my brokers in network for this failover testing:

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

I am using ActiveMQ 5.5 version. And my client broker URL looks like this:

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   

Additionally here is my activemq config XML for one of the 4 brokers: amq1.xml

Can someone here please look into this problem and suggest me what mistake I am making in this setup.

Update:

To clarify further on how I am doing request-response in my code:

  1. I already use a per producer destination (i.e. temporary queue) and set this in reply-to header of every message.
  2. I am already sending a per message unique correlation identifier in JMSCorrelationID header.
  3. As far as I know even Camel and Spring are also using temporary queue for request-response mechanism. Only difference is that Spring JMS implementation creates and destroys temporary queue for every message whereas I create temporary queue for the lifetime of the producer. This temporary queue is destroyed when client (producer) app shutsdown or by the AMQ broker when it realizes there are no active producer attached with this temporary queue.
  4. I am already setting a message expiry on each message on Producer side so that message is not held up in a queue for too long (60 sec).
like image 878
anubhava Avatar asked Jun 21 '11 22:06

anubhava


People also ask

What is failover in ActiveMQ?

The Failover transport randomly chooses one of the composite URIs and attempts to establish a connection to it. If it does not succeed, or if it subsequently fails, a new connection is established choosing one of the other URIs randomly from the list. Configuration Syntax.

How many queues can ActiveMQ handle?

There is no arbitrary limit on the number of queues. The only limitation is the resources available to the JVM as each new queue will consume heap memory not just for the messages in the queue but for the queue's own data-structures.

What is the difference between ActiveMQ and ActiveMQ Artemis?

Generally speaking, ActiveMQ Artemis is notably faster than ActiveMQ "Classic" due to the significant architectural differences between them. In short, ActiveMQ Artemis was designed to be completely non-blocking and performs very well at scale compared to ActiveMQ "Classic".


2 Answers

There is a broker attribute, org.apache.activemq.broker.BrokerService#cacheTempDestinations that should help in the failover: case. Set that to true in xml configuration, and a temp destination will not be removed immediately when a client disconnects. A fast failover: reconnect will be able to producer and/or consume from the temp queue again.

There is a timer task based on timeBeforePurgeTempDestinations (default 5 seconds) that handles cache removal.

One caveat though, I don't see any tests in activemq-core that make use of that attribute so I can't give you any guarantee on this one.

like image 189
gtully Avatar answered Sep 26 '22 08:09

gtully


Temporary queues are created on the broker to which the requestor (producer) in your request-reply scenario connects. They are created from a javax.jms.Session, so on that session disconnecting, either because of client disconnect or broker failure/failover, those queues are permanently gone. None of the other brokers will understand what is meant when one of your consumers attempts to reply to those queues; hence your exception.

This requires an architectural shift in mindset assuming that you want to deal with failover and persist all your messages. Here is a general way that you could attack the problem:

  1. Your reply-to headers should refer to a queue specific to the requestor process: e.g. queue:response.<client id>. The client id might be a standard name if you have a limited number of clients, or a UUID if you have a large number of these.
  2. The outbound message should set a correlation identifier (simply a sting that lets you associate a request with a response - requestors after all might make more than one request at the same time). This is set in the JMSCorrelationID header, and ought to be copied from the request to the response message.
  3. The requestor needs to set up a listener on that queue that will return the message body to the requesting thread based on that correllation id. There is some multithreading code that needs to be written for this, as you'll need to manually manage something like a map of correlation ids to originating threads (via Futures perhaps).

This is a similar approach to that taken by Apache Camel for request-response over messaging.

One thing to be mindful of is that the queue will not go away when the client does, so you should set a time to live on the response message such that it gets deleted from the broker if it has not been consumed, otherwise you will get a backlog of unconsumed messages. You will also need to set up a dead letter queue strategy to automatically discard expired messages.

like image 34
Jakub Korab Avatar answered Sep 23 '22 08:09

Jakub Korab