Loading balancing consumers on topics on ActiveMQ Artemis - jms

I am using ActiveMQ Artemis 2.10 and JMS Client 1.1 client.
If I used the multicast routing type on my address and needed durable subscriptions, how do I achieve load balancing on the consumer side?
With ActiveMQ 5 it would be virtual destinations.
It is unclear how a consumer side load-balancing could be achieved with ActiveMQ Artemis 7.2 and JMS Client 1.1 client when consuming off durable subscriptions on a topic.
In the example above:
Each of the consumers would set the clientId (client123 and client456) in the example, but this would mean there can be only one instance of client123 consuming from client123.topic.foo.
My current understanding is that ActiveMQ Artemis 2.10 and JMS Client 1.1 client implies you cannot have load balancing on topics, would that be correct?
The only option seems to be ActiveMQ Artemis 2.10 and JMS Client 2.0 which allows you to create Shared Durable subscriptions, would that be correct?
Is there a 3rd option?

My current understanding is that Active MQ Artemis 7.2 and JMS Client 1.1 client implies you cannot have load balancing on topics, would that be correct?
No.
The only option seems to be Active MQ Artemis 7.2 and JMS Client 2.0 which allows you to create Shared Durable subscriptions, would that be correct?
No.
Is there a 3rd option?
Yes. You can use the durable subscription's fully qualified queue name with a JMS consumer. As noted in the JMS-to-core mapping document, a JMS topic is mapped to a core address and a subscription on that JMS topic is mapped to a core queue on the core address. In the case of a durable JMS subscription the name of that queue follows the pattern "<clientID>.<subscriptionName>". Here's some example code to demonstrate:
ConnectionFactory cf = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
Connection connection1 = cf.createConnection();
connection1.setClientID("myClientID");
Session session1 = connection1.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = new ActiveMQTopic("myTopic");
MessageConsumer consumer1 = session1.createDurableSubscriber(topic, "mySubscriptionName");
Connection connection2 = cf.createConnection();
Session session2 = connection2.createSession();
Destination destination = new ActiveMQQueue("myTopic::myClientID.mySubscriptionName");
MessageConsumer consumer2 = session2.createConsumer(destination);
// Send 2 messages
MessageProducer producer = session1.createProducer(topic);
producer.send(session1.createMessage());
producer.send(session1.createMessage());
producer.close();
// Receive the first message with the first consumer
connection1.start();
Message message1 = consumer1.receive();
consumer1.close();
// Receive the second message with the second consumer
connection2.start();
Message message2 = consumer2.receive();
consumer2.close();
To say it another way...
Since JMS 1.1 doesn't explicitly allow shared durable subscriptions then you can't horizontally scale applications using createDurableSubscriber on the same topic with the same client identifier and subscription name. However, you can scale horizontally if one application uses createDurableSubscriber and all the others simply consume directly from the underlying subscription queue using its "fully qualified queue name" (which is derived from the client identifier and subscription name used when it was first created using createDurableSubscriber).

Related

Use same JMS ClientID for multiple destinations/topics

I'm working on an new application that subscribes to two topics on a JBoss 4 and processes incoming messages. Actually I'm using two DefaultMessageListenerContainer with durable subscriptions for the connection.
When I use the same ClientID for the durable Subscription the Container fails with the error:
2021-07-02T10:28:05.487+0200 [DefaultMessageListenerContainer-1] ERROR org.springframework.jms.listener.DefaultMessageListenerContainer - Could not refresh JMS Connection for destination 'TOPIC.providerDurableTopic' - retrying using FixedBackOff{interval=5000, currentAttempts=0, maxAttempts=unlimited}. Cause: This client id 'ka03.9971.mueller.de' is already registered!
Are there any possibilities two use the same clientId for two different destinations. Is there maybe any other ListenerContainer that can handle multiple destinations with one container instance?
The reason we try to use the same clientId is because we try to replace an old application with it subscriptions. This old application connected to the topics within one JMS transaction and was able to use the same client id.
I guess one possible solution is to use the SingleConnectionFactory and set the clientId on it. So only one Connection will be used for both Topics
The JMS 1.1 specification explicitly prohibits multiple connections with the same Client ID. I see three potential solutions to your problem:
Each message listener can use a connection with a unique Client ID.
Both message listeners can use the same connection.
Upgrade to a JMS 2 broker (e.g. ActiveMQ Artemis). JMS 2 relaxed the requirements for durable subscriptions and Client ID is no longer strictly required.

Multiple instances of the same Springboot application but only 1 instance consumes messages from ActiveMQ queue

I am running multiple instances of the same Spring Boot 2.0.4 Application, for scaling purposes, that consume messages from an ActiveMQ queue using the following:
#JmsListener(destination = "myQ")
Only the first consumer receives messages and if I stop the first consumer the second instance starts receiving the messages. I want each consumer to consume a message, not the same message, in a round robin fashion. But only the first consumer consumes messages.
It sounds like you want a JMS Topic rather than a Queue. You should also research durable subscriptions, shared subscriptions, and durable topics before you settle on the configuration you need for your setup.
See:
JMS API Programming Model (Search for JMS Message Consumers)
Queues vs Topics
Durable Queues and Topics

What does Spring JMS ActiveMQ use to determine when a broker should switch Exclusive Consumers?

An exclusive consumer in Activemq is one that is sent every message from a broker until the consumer dies or goes away, at which time the broker switches consumer.
What is it that defines when the switchover takes place? How do you configure this in Spring JMS/ActiveMQ?
It's not Spring JMS doing the checking; it's the JMS provider, ActiveMQ.
JMS is an API specification; an empty framework, essentially. ActiveMQ provides the implementation backing for managing connections, message brokering, load-balancing, fail-over, etc.
The ActiveMQ broker handles switching-over consumers based on queue properties (you don't need to do anything special in your code):
queue = new ActiveMQQueue("TEST.QUEUE?consumer.exclusive=true");
The switch-over takes place when either the consumer disconnects gracefully or the broker determines that the consumer has disappeared (via the wireFormat.maxInactivityDuration elapsing without any messages or keep-alives being received). You don't have to configure anything if you're happy with the default value of wireFormat.maxInactivityDuration (30 seconds), but you can tweak that if you want to change how long it takes before the broker gives up on a client.

How can i change activeMQ persistence adapter without data loss?

I need to change activemq persistence adapter from AMQ to KahaDB, but it's not acceptable to loose all undelivered messages stored via AMQAdapter. Is there any way to automatically use old adapter to send undelivered messages and then switch to KahaDB store?
The general solution to this is to create a new Broker instance and network the old broker and the new one. Once the brokers are networked you create a consumer on the new broker for the destinations and allow the demand to drain the mesasge's from old to new Broker.
Refer to this thread for more:

single jms consumer for multiple jms servers

I am using a distributed jms queue and weblogic is my app server. There are three jms servers deployed in my clustered enviroment. The producers just send the message using name of queue jndi lookup 'udq' for example. Now I have associated a consumer for each jms server and I was able to consume the message, no problem so far.
Here is question, can I have a single consumer to consume the messages from the 3 jms servers. The weblogic allows jndi naming for destination lookup with following syntax #
qsession1 = qcon1.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
qsession2 = qcon2.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
qsession3 = qcon3.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queue1 = (Queue)ctx.lookup("JMSServer-1#UDQ");
queue2 = (Queue)ctx.lookup("JMSServer-2#UDQ");
queue3 = (Queue)ctx.lookup("JMSServer-3#UDQ");
qreceiver1 = qsession1.createReceiver(queue1);
qreceiver2 = qsession2.createReceiver(queue2);
qreceiver3 = qsession3.createReceiver(queue3);
qreceiver1.setMessageListener(this);
qreceiver2.setMessageListener(this);
qreceiver3.setMessageListener(this);
qcon1.start();
qcon2.start();
qcon3.start();
I have only one OnMessage implemented for the above consumer. This does not work. Any suggestions please..
No, you can't have a consumer receiving messages from more than one JMS server. A consumer can receive messages from only one JMS server. You need to create multiple consumers to receive messages from multiple JMS servers.
you can use "Queue Forwarding" function.
From online documentation of wls 10.3:
"Queue members can forward messages to other queue members by configuring the Forward Delay attribute in the Administration Console, which is disabled by default. This attribute defines the amount of time, in seconds, that a distributed queue member with messages, but which has no consumers, will wait before forwarding its messages to other queue members that do have consumers."
here a link: http://docs.oracle.com/cd/E13222_01/wls/docs103/jms/dds.html#wp1260816
You can configure this feature from administration of each single queue.

Resources