Search code examples
jmsactivemq-artemisjms-topic

Loading balancing consumers on topics on ActiveMQ Artemis


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?

Publish-Subscribe

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?


Solution

  • 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).