Coding a JMS client to an Artemis JMS cluster

This tutorial demonstrates how to code a remote JMS client application which connects to an Artemis AMQ Broker and how to balance connections on the server side.

The provided code (taken from artemis examples) demonstrates how to connect to an Artemis clustered broker, sending and receiving messages from a queue. It also shows how the distribution of messages between multiple servers in the cluster works.

Include the Artemis Client dependencies

Firstly, add the your pom.xml the libraries to connect to the Artemis Server

<dependency>
         <groupId>org.apache.activemq</groupId>
         <artifactId>artemis-jms-client</artifactId>
         <version>${artemis.version}</version>
</dependency>

Code the JMS Client

Next, add the following ClusteredQueueExample that shows how to create a Connection to the two nodes of a Cluster and send a message to one node. Artemis will load balance the messages between the cluster nodes:

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;


public class ClusteredQueueExample {

   public static void main(final String[] args) throws Exception {
      Connection connection0 = null;

      Connection connection1 = null;

      try {
         // Step 2. Instantiate the Queue
         Queue queue = ActiveMQJMSClient.createQueue("exampleQueue");

         // Instantiate connection towards server 0
         ConnectionFactory cf0 = new ActiveMQConnectionFactory("tcp://localhost:61616");

         // Step 5. Look-up a JMS Connection Factory object from JNDI on server 1
         ConnectionFactory cf1 = new ActiveMQConnectionFactory("tcp://localhost:61617");

         // Step 6. We create a JMS Connection connection0 which is a connection to server 0
         connection0 = cf0.createConnection();

         // Step 7. We create a JMS Connection connection1 which is a connection to server 1
         connection1 = cf1.createConnection();

         // Step 8. We create a JMS Session on server 0
         Session session0 = connection0.createSession(false, Session.AUTO_ACKNOWLEDGE);

         // Step 9. We create a JMS Session on server 1
         Session session1 = connection1.createSession(false, Session.AUTO_ACKNOWLEDGE);

         // Step 10. We start the connections to ensure delivery occurs on them
         connection0.start();

         connection1.start();

         // Step 11. We create JMS MessageConsumer objects on server 0 and server 1
         MessageConsumer consumer0 = session0.createConsumer(queue);

         MessageConsumer consumer1 = session1.createConsumer(queue);

         Thread.sleep(1000);

         // Step 12. We create a JMS MessageProducer object on server 0
         MessageProducer producer = session0.createProducer(queue);

         // Step 13. We send some messages to server 0

         final int numMessages = 10;

         for (int i = 0; i < numMessages; i++) {
            TextMessage message = session0.createTextMessage("This is text message " + i);

            producer.send(message);

            System.out.println("Sent message: " + message.getText());
         }

         // Step 14. We now consume those messages on *both* server 0 and server 1.
         // We note the messages have been distributed between servers in a round robin fashion
         // JMS Queues implement point-to-point message where each message is only ever consumed by a
         // maximum of one consumer

         for (int i = 0; i < numMessages; i += 2) {
            TextMessage message0 = (TextMessage) consumer0.receive(5000);

            System.out.println("Got message: " + message0.getText() + " from node 0");

            TextMessage message1 = (TextMessage) consumer1.receive(5000);

            System.out.println("Got message: " + message1.getText() + " from node 1");
         }
      } finally {
         // Step 15. Be sure to close our resources!

         if (connection0 != null) {
            connection0.close();
         }

         if (connection1 != null) {
            connection1.close();
         }
      }
   }
}

This example uses a JMS queue deployed on two different nodes. The two nodes are configured to form a cluster.

<cluster-connection name="my-cluster">
   <connector-ref>netty-connector</connector-ref>
   <retry-interval>500</retry-interval>
   <use-duplicate-detection>true</use-duplicate-detection>
   <message-load-balancing>STRICT</message-load-balancing>
   <max-hops>1</max-hops>
   <discovery-group-ref discovery-group-name="my-discovery-group"/>
</cluster-connection>

We then send some messages via the producer, and we verify that both consumers receive the sent messages in a round-robin fashion. This examples demonstrates how ActiveMQ Artemis load balances the sent messages across all consumers on the cluster

Connection Failover

To connect to the cluster, it is sufficient to provide a single hostname which needs to be available when you initiate the connection. If you want to use more than one broker as a possible initial connection, group the host:port entries as in the following example:

(tcp://host1:port,tcp://host2:port)?ha=true&reconnectAttempts=3

You can include the name-value pair ha=true as part of the query string to ensure the client receives information about each master and slave broker in the cluster.
Finally, include the name-value pair reconnectAttempts=n, where n is an integer greater than 0. This parameter sets the number of times the client attempts to reconnect to a broker.

Found the article helpful? if so please follow us on Socials