10 Replies Latest reply on Dec 24, 2010 10:15 AM by Khurram Majeed

    JMS Topic with high availability for the client?

    balmark1 Newbie

      Hey,

      Can anyone help me, I'm looking to find out if this is possible.

      Can I have a client app, listening on a JMS topic, so that the client app can be setup in some way with some high availability?

      The scenario..

      I am producing messages and publishing them on a topic, from here, I  have a few applications listening and actioning based on the message  which is all good.
      This message is a status message that multiple applications need to work with, so a topic is the proper message type here.

      Now.. the problem

      I have an application listening to this topic.. but I can't see a way to  make this highly available.. if I have multiple instances of this  application, they'll both be reading the same message since they'd be  reading from the same topic.. (eg. If I've jboss instances on 2 seperate  machines with an MDB running off the topic.. if instance 1 goes down, I  need instance 2 to be able to take over or have both doing some round  robin.. I know this is what a queue is for, but its a topic I have to  work with for the initial listener as this isn't the only application  listening.. )

      Basically, as it is, this is a single point of failure for me.. Is there any way to have High Availability on the client, when working with a 'Topic' ?


      I asked about and got a response saying that this is possible using Glassfish cluster with a MDB deployed with a 'shared subscription'.. does JBoss have any similar facility or anyone have any suggestions on how to go about this?

       

      Something small and simple that's HA, could for my purposes just be used to throw these messages onto a queue which I could then implement some form of HA, but its the initial topic that's giving me cause for concern.

       

      Help me please!

      Bal

        • 1. Re: JMS Topic with high availability for the client?
          Wolf-Dieter Fink Master

          What version of JBoss do you use?

          You can configure the message destination as 'clustered', are you sure this is configured?

          • 2. Re: JMS Topic with high availability for the client?
            balmark1 Newbie

            Hey Wolf,

             

            Thanks for the reply

             

            Currently using Jboss 4.2.3 here 

             

            The Message Queue I'm using however is the latest that comes with the Sun JDK.

            If I want to get what I want here, do I have to move from the standard JMS framework? I was assuming that the solution would have to lie with the app server. Configuring a message destination as 'clustered' .. where are you saying this should be done?

             

            I'm flexible here if there's a solution, ie. I can create a HA app for the sole purpose of taking messages off a topic and placing them on a queue for app servers that are sitting in parallel, this HA app doesnt need to be JBoss 4.2.3..

            • 3. Re: JMS Topic with high availability for the client?
              Bernd Eckenfels Novice

              I think it should work with durable subsriptions where you specify a clirntid and subscrption name. But I am not sure if HornetMQ or JBossMQ allow multiple subsribed consumers with the same ID or if it will disconnect one of it.

               

              http://community.jboss.org/wiki/WhatIsTheCorrectWayToMakeADurableSubscription

              1 of 1 people found this helpful
              • 4. Re: JMS Topic with high availability for the client?
                Wolf-Dieter Fink Master

                Oh,

                JBoss 4.2 use JBossMQ by default.

                In this case you have not really a clustered JMS, it is only a HA-singleton, this mean that only one JBoss starts the MQ part, if this node will fail one of the other nodes will start the MQ part.

                AFAIK there is no configuration for clustered destinations.

                 

                Also I'm not really sure how the behaviour is if the MQ fail, it might be that you have to catch the Exception and re-connect via JNDI lookup.

                • 5. Re: JMS Topic with high availability for the client?
                  Wolf-Dieter Fink Master

                  Hi Bernd,

                  a durable topicis not for this.

                  This mean that you connect to such topic an, no matter whether you disconnect, the JMS server store each message of the topic for you as long as you ack it.

                  • 6. Re: JMS Topic with high availability for the client?
                    balmark1 Newbie

                    Ah, jboss 4.2 might use JBossMQ by default, but I had it setup for suns messaging queue which is now glassfish messaging queue I think and can be setup as a proper jms cluster (I think at the time, the jboss message queue wasn't really upto what were looking for, but it might be now )

                     

                    Lads over in the Sun site suggested http://community.jboss.org/message/438958?tstart=1 for jboss, but also mentioned glassfish app server and MQ allow shared 'subscriptions'

                     

                    Thanks for all the info, I hope it'll be as helpful to someone who lands here via google with the same dilema

                     

                    /Bal

                    • 7. Re: JMS Topic with high availability for the client?
                      Bernd Eckenfels Novice

                      Hallo Wolf-Dieter,

                       

                      I know what a Topic is, and I know that when you use same client id and subscription name that you can have multiple subscribers and exactly one of them gets the message. This is what Bal asked about.

                       

                      Gruss

                      Bernd

                      • 8. Re: JMS Topic with high availability for the client?
                        balmark1 Newbie

                        Hey Bernd,

                         

                        I checked it out, if I wanted to stay clear of clustered web apps and do something really simple, I could do it using durable topics alright!

                        ie. have 2-3-4-5 servers whatever.. all sitting out on their own.. just waiting for the opportunity to take over

                         

                        only 1 can subscribe to the topic with the same client id (without doing clustering on the web apps)

                        so 'hot standby' would be very much 'egar hot standby' .. it'd be possible (I'm assuming not recommended at all tho) ..

                        that each of the standby servers continously try to connect using the same clientid.. so if the current one drops, the missed messages will be waiting for the next server to manage the connection

                         

                        I'll be looking at clustered webapps though the idea of the above seems a little 'wrong' .. but it'd work I think..

                        • 9. Re: JMS Topic with high availability for the client?
                          balmark1 Newbie

                          OK another bit .. 

                          Which is alot nicer all together!

                           

                          If I setup the topic service as

                           

                          <server>

                              <mbean code="org.jboss.jms.server.destination.TopicService"

                                  name="jboss.messaging.destination:service=Topic,name=MyTopic"

                                  xmbean-dd="xmdesc/Topic-xmbean.xml">

                                  <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>

                                  <depends>jboss.messaging:service=PostOffice</depends>

                                  <attribute name="SecurityConfig">

                                      <security>

                                          <role name="guest" read="true" write="true" create="true"/>

                                          <role name="publisher" read="true" write="true" create="false"/>

                                          <role name="durpublisher" read="true" write="true" create="true"/>

                                          <role name="test" read="true" write="true" create="true"/>

                                      </security>

                                  </attribute>

                                  <attribute name="Clustered">true</attribute>

                              </mbean>

                          </server>

                           

                          I can attach with multiple clientids .. and the message gets  distributed over all my standby servers.. one goes down, and the others  just take the load.. lovely 

                           

                          Without clustered = true in the topic, if I tried to connect multiple subscribers with the same clientid.. I'd get

                           

                          javax.jms.IllegalStateException: Cannot create a subscriber on the durable subscription since it already has subscriber(s)

                           

                           

                          with  clustered = true with the jbossmq, (havent tried with other mq's), I  can subscribe lots of times with the same clientid and it works as I'd  like it to  .. lovely jubley 

                           

                           

                          eg. with the above myjms-service.xml file in the deploy folder, I can run 2 apps to test it..

                           

                          eg of a test publisher -

                           

                           

                          package com.c.jms.testing;

                           

                          import java.util.Hashtable;

                          import java.util.Properties;

                          import javax.jms.JMSException;

                          import javax.jms.Queue;

                          import javax.jms.QueueConnection;

                          import javax.jms.QueueConnectionFactory;

                          import javax.jms.QueueSender;

                          import javax.jms.QueueSession;

                          import javax.jms.Session;

                          import javax.jms.TextMessage;

                          import javax.jms.Topic;

                          import javax.jms.TopicConnection;

                          import javax.jms.TopicConnectionFactory;

                          import javax.jms.TopicPublisher;

                          import javax.jms.TopicSession;

                          import javax.naming.Context;

                          import javax.naming.InitialContext;

                          import javax.naming.NamingException;

                           

                          public class CreateDurableTopic {

                              /**

                               * @param args

                               */

                           

                              public static void main(String[] args) {

                                  String                  topicName = "/topic/MyTopic";

                                  Context                 jndiContext = null;

                                  TopicConnectionFactory  topicConnectionFactory = null;

                                  TopicConnection         topicConnection = null;

                                  TopicSession            topicSession = null;

                                  Topic                   topic = null;

                                  TopicPublisher          topicSender = null;

                                  TextMessage             message = null;

                                  final int               NUM_MSGS;

                           

                                  try {

                           

                                     Properties env = new Properties();

                                      env.put(Context.INITIAL_CONTEXT_FACTORY,

                                          "org.jnp.interfaces.NamingContextFactory");

                                      env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming.client");

                                      env.put(Context.PROVIDER_URL, "jnp://localhost");

                           

                                      jndiContext = new InitialContext(env);

                                  } catch (NamingException e) {

                                      System.out.println("Could not create JNDI API " +

                                          "context: " + e.toString());

                                      System.exit(1);

                                  }

                           

                           

                                  try {

                           

                                      topicConnectionFactory = (TopicConnectionFactory)

                                          jndiContext.lookup("ConnectionFactory");

                                      topic = (Topic) jndiContext.lookup(topicName);

                                  } catch (NamingException e) {

                           

                                      System.out.println("JNDI API lookup failed: " +

                                          e.toString());

                                      System.exit(1);

                                  }

                           

                                  try {

                                      topicConnection =

                                          topicConnectionFactory.createTopicConnection("guest", "guest");

                                      topicSession =

                                          topicConnection.createTopicSession(false,

                                              Session.AUTO_ACKNOWLEDGE);

                                      topicSender = topicSession.createPublisher(topic);

                                      message = topicSession.createTextMessage();

                           

                                      for (int i = 0; i < 50; i++) {

                                          message.setText("This is message " + (i + 1));

                                          System.out.println("Sending message: " +

                                              message.getText());

                                          topicSender.send(message);

                                          try{

                                              Thread.sleep(1000);

                                          }catch(Exception e){};

                                      }

                           

                                      topicSender.send(topicSession.createMessage());

                                  } catch (JMSException e) {

                                      System.out.println("Exception occurred: " +

                                          e.toString());

                                  } finally {

                                      if (topicConnection != null) {

                                          try {

                                              topicConnection.close();

                                          } catch (JMSException e) {}

                                      }

                                  }

                             }

                          }

                           

                          and  eg of a test listeners (run multiple times, have a few running.. run the  publisher.. stop a few of the listeners and you'll see the others  taking over etc.)

                           

                           

                          package com.c.jms.testing;

                           

                          import java.util.Hashtable;

                          import java.util.Properties;

                           

                          import javax.jms.JMSException;

                          import javax.jms.Message;

                          import javax.jms.MessageListener;

                          import javax.jms.Topic;

                          import javax.jms.TopicConnection;

                          import javax.jms.TopicConnectionFactory;

                          import javax.jms.TopicSubscriber;

                          import javax.jms.TopicSession;

                          import javax.jms.Session;

                          import javax.jms.TextMessage;

                          import javax.naming.Context;

                          import javax.naming.InitialContext;

                          import javax.naming.NamingException;

                           

                          public class TopicListenerApplication implements MessageListener {

                           

                              public TopicListenerApplication(){

                           

                              }

                           

                              /**

                               * @param args

                               */

                              public static void main(String[] args) {

                           

                                    String                  topicName = null;

                                      Context                 jndiContext = null;

                                      TopicConnectionFactory  topicConnectionFactory = null;

                                      TopicConnection         topicConnection = null;

                                      TopicSession            topicSession = null;

                                      Topic                   topic = null;

                                      TopicSubscriber         topicReceiver = null;

                                      TextMessage             message = null;

                           

                                      topicName = "/topic/MyTopic";

                                      System.out.println("Topic name is " + topicName);

                           

                                      TopicListenerApplication listener = new TopicListenerApplication();

                                      /*

                                       * Create a JNDI API InitialContext object if none exists

                                       * yet.

                                       */

                                      try {

                                          Properties env = new Properties();

                                          env.put(Context.INITIAL_CONTEXT_FACTORY,

                                              "org.jnp.interfaces.NamingContextFactory");

                                          env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming.client");

                                          env.put(Context.PROVIDER_URL, "jnp://localhost");

                           

                                          jndiContext = new InitialContext(env);

                           

                                      } catch (NamingException e) {

                                          System.out.println("Could not create JNDI API " +

                                              "context: " + e.toString());

                                          System.exit(1);

                                      }

                           

                                      try {

                                          topicConnectionFactory = (TopicConnectionFactory)

                                              jndiContext.lookup("ConnectionFactory");

                                          topic = (Topic) jndiContext.lookup(topicName);

                                      } catch (NamingException e) {

                                          System.out.println("JNDI API lookup failed: " + e.toString());

                                          System.exit(1);

                                      }

                           

                                      try {

                                          topicConnection = topicConnectionFactory.createTopicConnection("guest", "guest");

                                          topicConnection.setClientID("testclient");

                                          topicConnection.start();

                                          topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

                                          topicReceiver = topicSession.createDurableSubscriber(topic, "guest", null, false);//Subscriber(topic);

                                          topicReceiver.setMessageListener(listener);

                           

                                          while(true){

                                              Thread.sleep(1000);

                                          }

                                      } catch (JMSException e) {

                                          System.out.println("Exception occurred: " +

                                              e.toString());

                                      } catch(Exception e){

                           

                                      }

                                      finally {

                                          if (topicConnection != null) {

                                              try {

                                                  topicConnection.close();

                                              } catch (JMSException e) {}

                                          }

                                      }

                                  }

                           

                           

                              public void onMessage(Message message){

                                  System.out.println("Msg received "+message);

                                  if(message instanceof TextMessage){

                                      try{

                                          System.out.println(((TextMessage)message).getText());

                                      }catch(Exception e){

                                          e.printStackTrace();

                                      }

                                  }

                              }

                          }

                          1 of 1 people found this helpful
                          • 10. Re: JMS Topic with high availability for the client?
                            Khurram Majeed Newbie

                            Hey, I am also trying to setup a HA-Singleton topic, but 

                            my first instance starts  successfully but when  second node starts i am getting this exception,  one thing weird i have  noticed is that sometimes second node starts  smoothly, i dont get this  exception - i had to retry 4-5 times to start  the server. Can anyone  help me in this?

                             

                            Stacktrace:

                             

                            javax.jms.InvalidDestinationException: No such destination: JBossTopic[MyMessage] has it been deployed?
                                 at org.jboss.jms.server.endpoint.ServerSessionEndpoint.createConsumerDelegateInternal(ServerSessionEndpoint.java:1838)
                                 at org.jboss.jms.server.endpoint.ServerSessionEndpoint.createConsumerDelegate(ServerSessionEndpoint.java:252)
                                   at    org.jboss.jms.server.endpoint.advised.SessionAdvised.org$jboss$jms$server$endpoint$advised$SessionAdvised$createConsumerDelegate$aop(SessionAdvised.java:94)
                                 at

                             

                             

                            Can you please help me in this?

                            Khurram