5 Replies Latest reply on May 21, 2008 3:01 PM by wecucho

    HA-JNDI server side problem

    wecucho

      Hi all, first at all i am running JBoss 4.2.2 GA.

      I develop a few methods to obtain the master node for a cluster easily given at least a node and all works great outside the server (the reason i need the master node is to create and delete JMS queues).

      In my test enviroment i have a cluster with 2 nodes, A and B, and i have a web application deployed on both nodes who has the fancy buttons to see, create and remove my queues... so, i ported my tests code into the web component and fails obtaining the master node, i already read the documentation and i am doing exactly what they say without a positive result, my InitialContext always return the local instance for the node who runs the web component, so, if i start the web page in the master node all runs ok, by the other hand if i use the web pages in the Non Master node it will fail.

      My Nodes are:
      A = 192.168.5.63 (MASTER)
      B = 192.168.5.52 (Non Master)

      The magic button who try to obtain the correct Master Node has the following code (just as the documentation says):



      public static MBeanServerConnection getMasterNodeFromCluster(int tries, String node) {

      try {

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

      Properties env = new Properties();
      env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
      env.put(Context.URL_PKG_PREFIXES, "jboss.naming:org.jnp.interfaces");
      env.put(Context.PROVIDER_URL, node);
      System.out.print("trying with " + node);

      Context ctx = new InitialContext(env);
      MBeanServerConnection mbs = (MBeanServerConnection) ctx.lookup("jmx/invoker/RMIAdaptor");

      System.out.print(" obtained "
      + mbs.getAttribute(new ObjectName("jboss:service=HAJNDI"), "BindAddress").toString());

      if (mbs.getAttribute(new ObjectName("jboss.ha:service=HASingletonDeployer"), "MasterNode").toString()
      .equalsIgnoreCase("true")) {
      System.out.println();
      return mbs;
      }
      }

      } catch (Exception e) {
      e.printStackTrace();
      }

      System.out.println("not found");

      return null;

      }





      and i am calling this method from the action of the button this way:



      JMQueuesUtils.getMasterNodeFromCluster(10, "192.168.5.63:1100");



      Don't pay any attention to the 'tries' variable, that was just a test...

      The Cluster Guide for JBoss 4.2 says literally this:


      So, an EJB home lookup through HA-JNDI, will always be delegated to the local
      JNDI instance. If different beans (even of the same type, but participating in different
      clusters) use the same JNDI name, it means that each JNDI server will have a
      different "target" bound (JNDI on node 1 will have a binding for bean A and JNDI
      on node 2 will have a binding, under the same name, for bean B). Consequently, if
      a client performs a HA-JNDI query for this name, the query will be invoked on any
      JNDI server of the cluster and will return the locally bound stub. Nevertheless, it may
      not be the correct stub that the client is expecting to receive!


      and ....

      If you want to access HA-JNDI from inside the application server, you must explicitly
      get an InitialContext by passing in JNDI properties. The following code shows how to
      create a naming Context bound to HA-JNDI:
      Properties p = new Properties();
      p.put(Context.INITIAL_CONTEXT_FACTORY,
      "org.jnp.interfaces.NamingContextFactory");
      p.put(Context.URL_PKG_PREFIXES,
      "jboss.naming:org.jnp.interfaces");
      p.put(Context.PROVIDER_URL, "localhost:1100"); // HA-JNDI port.
      return new InitialContext(p);


      im doing exactly this but simply does not work... :(

      Thanks in advance! and forgive my english.

        • 1. Re: HA-JNDI server side problem
          brian.stansberry

          Your English is fine; if you hadn't apologized for it I'd have figured you were a native speaker. :)

          "wecucho" wrote:

          and i am calling this method from the action of the button this way:



          JMQueuesUtils.getMasterNodeFromCluster(10, "192.168.5.63:1100");




          Where does this "192.168.5.63" value come from? Does your app somehow know the IP addresses of the cluster members?

          If so, change it to use regular JNDI (1099) not HA-JNDI:

          JMQueuesUtils.getMasterNodeFromCluster(10, "192.168.5.63:1099");
          


          It sounds like what you want is a regular JNDI lookup of a particular node. You don't want HA; i.e. if that node isn't able to respond you don't want to connect to some other node. If you use HA, you can't control what node it's going to do the lookup on; it will either try to optimize locally or will load balance, neither of which gives you the guaranteed answer I *think* you want.

          • 2. Re: HA-JNDI server side problem
            wecucho

            Thanks for your reply, i test what you say but that does not work :(, still respond the same node which is running the method, i think are a kind of "affinity" that make the InitialContext to use the local or something.

            Im gonna to explain the problem better but i think that its difficult to see yet, i create a simple method to determine which exactly node is the master node of a cluster give a node of it or several nodes using the HA-JNDI port of course (does not mather IF i use Round Robin Balance *), and it works great OUTSIDE the cluster, the method start to lookup and the nodes start to respond in the round robin way, so, in my test enviroment that tooks 2 iteration tops.. for instance, i start looking for the master and..

            1.- respond the master: thats it, i have the master at first time
            2.- respond the other node: upps i have the MasterNode in false and return, my method is gonna lookup again and for the balance (Round Robin) the master will respond...

            As my program is a kind of Queue manager, he needs to dynamically creates and delete queues, so it needs the "jboss.mq:service=DestinationManager" who lives only in the MASTER node, so i can execute operations like:


            mbsMaster.invoke(destinationManager, "createQueue", new Object[] { name, name }, new String[] {
            String.class.getName(), String.class.getName() });


            and


            mbsMaster.invoke(destinationManager, "destroyQueue", new Object[] { name}, new String[] {
            String.class.getName()});


            When i try your suggestion this was my result...


            2008-05-21 08:11:10,899 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,952 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,953 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,955 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,955 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,957 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,957 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,959 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,959 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,961 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,961 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,963 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,964 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,965 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,966 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,968 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,972 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,973 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,974 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:11:10,975 INFO [STDOUT] obtained 192.168.5.52
            2008-05-21 08:11:10,976 INFO [STDOUT] not found


            He was trying to look directly in the master node but for some mysterious and divine reason that only god is able to answer that lookup obtain the local Context, if i run the same test in the master node directly i get:


            2008-05-21 08:15:11,499 INFO [STDOUT] trying with 192.168.5.63:1099
            2008-05-21 08:15:11,552 INFO [STDOUT] obtained 192.168.5.63
            2008-05-21 08:15:11,632 INFO [STDOUT] MASTER found!


            There has to be some kind of affinity as i said before that make this happend, and my best guest is that have to be a way to disable this behavior in the jboss, or mabye there have to be a different way to ask for the master..

            Thanks for your time :)

            Maybe with this additional info your or anyone can see my problem better.

            * If my balance is Round Robin the only thing i have to do is ask for a resource (lookup --> ctx.lookup("jmx/invoker/RMIAdaptor")) and get the MasterNode variable and if TRIES is bigger than the number of the nodes in the cluster ill gonna get the master node in some point.

            • 3. Re: HA-JNDI server side problem
              wecucho

              Sorry man, when i test your suggestion i had commented the line


              env.put(Context.PROVIDER_URL, node);


              jeje :S, so i re-tested and he find the node, but still in the hard way, i mean, in my environment test i have 2 nodes and i know the master, but in the future ill gonna have X nodes and i dont be able to know exactly which is the master.

              Thanks ;)

              • 4. Re: HA-JNDI server side problem
                brian.stansberry

                Yes, the HA-JNDI client includes an optimization to route the call locally if the client is in the same VM as the server.

                OK, now I understand your use case better. Here's a workaround:

                Use HA-JNDI to get an MBeanServerConnection. Invoke on it to get the "CurrentView" attribute of the "jboss:service=DefaultPartition" mbean. That will return you a Vector. Iterate through the vector and call getName() on each element; that returns a string with the JNDI address and port of that member of the cluster. You can then do a regular JNDI lookup using that string as your PROVIDER_URL.

                • 5. Re: HA-JNDI server side problem
                  wecucho

                  Thanks Brian, really i appreciate your time and help, now i understand better this part of clustering and have my app working fine, again thanks.

                  Best Regards,