1 2 Previous Next 24 Replies Latest reply on Jul 7, 2011 3:19 AM by ronsen

    JNDI Lookup in JBoss Cluster

    nitin_jain

      Hello Forum,

      I am in the process of deploying an application in a clustered environment. I have the war file deployed on 2 separate
      machine running Apache Tomcat servers. The load balancing is achieved using Apache HTTP Server with mod_jk.
      I have another set of 2 machines (Windows Servers) that run JBoss5.1.0 which, are just used for EJB and JMS. A Windows NLB
      is used to provide load balancing for the two AS.
      Cluster.jpg

       

      The JBoss servers are started using the following parameters.

      JBoss Node 1 192.168.0.1


      JBoss Node 2 192.168.0.2


      NLB VIP 192.168.0.3

      If I set java.naming.provider.url to jnp://192.168.0.1:1099/ or jnp://192.168.0.2:1099/
      JNDI lookup is successful. However, if I set java.naming.provider.url to jnp://192.168.0.3, the following error is thrown.

      Please advice.

       

      Best Regards,

      Nitin

        • 1. Re: JNDI Lookup in JBoss Cluster
          wdfink

          I recommend to drop the NLB, it bring more complexity. (Also I do not know somthing about it )

          I suppose the service change the IP addresses.

           

          If you start the JBoss instances as you show your instances build a JBoss-cluster (if multicast is possible between it)

          From you client (WAR) you can set "192.168.0.1:1100,192.168.0.2:1100" and it works.

           

          JBoss provide dynamic connections in its interface and a translation of a third-party harm this.

          • 2. Re: JNDI Lookup in JBoss Cluster
            nitin_jain

            Thank you for your response.

             

            I introduced NLB before 2 AS to enable load balancing. I there a better way to achieve it, because if I set “java.naming.provider.url=jnp://192.168.0.1:1099/192.168.0.2:1099/”, all the requests will be routed to “192.168.0.1” till the time it is not available.

             

            Load balancing requests routed to AS is quite important. Your suggestions will be highly appreciated.

             

            Regards,

            Nitin

            • 3. Re: JNDI Lookup in JBoss Cluster
              wdfink

              Is it a typo here or in your environment?

              Use "192.168.0.1:1099,192.168.0.2:1099"  ==> a ',' as separator!

              • 4. Re: JNDI Lookup in JBoss Cluster
                nitin_jain

                Sorry, it was a typo while sending my response. The code is correct "“java.naming.provider.url=jnp://192.168.0.1:1099,192.168.0.2:1099".

                 

                Regards,

                Nitin

                • 5. Re: JNDI Lookup in JBoss Cluster
                  wdfink

                  Then it looks like that your JBoss-cluster find not together as a cluster.

                  Normally, if you have one cluster member as JNDI lookup, nevertheless whether it is JNDI or HA-JNDI (HighAvailable), the proxy view is cluster aware and is loadbalanced.

                   

                  So check the logfiles after startup the first instance, you will find this log infos:

                    [DefaultPartition] Number of cluster members: 1

                    [DefaultPartition] Other members: 0

                   

                  If you start the second instance, the first will show an update of the log and the second show direct 'Number of cluster members: 2'.

                   

                  Could you check this?

                  • 6. Re: JNDI Lookup in JBoss Cluster
                    nitin_jain

                    Please refer to the logs below. I can view this log on 192.168.0.1.

                     

                    17:03:27,353 INFO  [ClusterTest] I am (192.168.0.1:1099) received membershipChanged event:
                    17:03:27,353 INFO  [ClusterTest] Dead members: 0 ([])
                    17:03:27,353 INFO  [ClusterTest] New Members : 1 ([192.168.0.2:1099])
                    17:03:27,368 INFO  [ClusterTest] All Members : 2 ([192.168.0.1:1099, 192.168.0.2:1099])

                     

                    I hope this will help.

                     

                    Reards,

                    Nitin

                    • 7. Re: JNDI Lookup in JBoss Cluster
                      wdfink

                      Mmmh,

                      from this point of view it looks good, the cluster view looks ok for me.

                      So I expect that the InitialContext will loadbalance the EJB calls.

                       

                      But, how do you create the InitialContext and the instance of the Remote-Proxy?

                      Do you create the InitialContext for each call or do you cache it?

                       

                      If you create it new than it can be the problem ...

                       

                      Also I recommend to use the HA-JNDI, it will be the default port 1100 instead of 1099

                      • 8. Re: JNDI Lookup in JBoss Cluster
                        nitin_jain

                        Please refer to the service locator implementation used in my application.

                         

                         

                        public abstract class ServiceLocator {
                            final private static SystemLog systemLog = getLoggerInstance(ServiceLocator.class);
                            final private static String JNDI_PREFIX = "app/";
                            final private static String JNDI_POSTFIX = "/remote";
                            final private static String JNDI_POSTFIX_LOCAL = "/local";
                            final private static String JNP_PARTITION_NAME = "jnp.partitionName";
                            private static Context initialContext;
                            public static Context getInitialContext() throws CustomException {
                                try {
                                    if (initialContext == null) {
                                        Properties properties = new Properties();
                                        properties.put(Context.INITIAL_CONTEXT_FACTORY, ConfigReader.getString(Context.INITIAL_CONTEXT_FACTORY));
                                        properties.put(Context.PROVIDER_URL, ConfigReader.getString(Context.PROVIDER_URL));
                                        properties.put(Context.SECURITY_CREDENTIALS, ConfigReader.getString(Context.SECURITY_CREDENTIALS));
                                        properties.put(SECURITY_PRINCIPAL, ConfigReader.getString(SECURITY_PRINCIPAL));
                                        properties.put(JNP_PARTITION_NAME, "ClusterTest");
                                        initialContext = new InitialContext(properties);
                                    }
                                    return initialContext;
                                } catch(NamingException namingException) {
                                    systemLog.error(namingException.toString());
                                    throw new CustomException(namingException);
                                }
                            }
                            public static Object getSessionRemoteObjectEJB3(String beanName, Class<?> businessRemote) throws CustomException {
                                return getSessionRemoteObjectEJB3(beanName, JNDI_PREFIX, businessRemote);
                            }
                            public static Object getSessionRemoteObjectEJB3(String beanName, String jndiPrefix, Class<?> businessRemote) throws CustomException {
                                return lookupEJB3(getInitialContext(), jndiPrefix + beanName + JNDI_POSTFIX + "-" + businessRemote.getName(), businessRemote);
                            }
                            public static Object getSessionRemoteObjectEJB3(String beanName) throws CustomException {
                                return lookupEJB3(getInitialContext(), JNDI_PREFIX + beanName + JNDI_POSTFIX);
                            }
                            public static Object getSessionLocalObjectEJB3(String beanName) throws CustomException {
                                return lookupEJB3(getInitialContext(), JNDI_PREFIX + beanName + JNDI_POSTFIX_LOCAL);
                            }
                            
                            public static Object lookupEJB3(Context context, String jndiName, Class<?> businessRemote) throws CustomException {
                                try {
                                    return PortableRemoteObject.narrow(context.lookup(jndiName), businessRemote);
                                } catch(NamingException namingException) {
                                    throw new CustomException(NAMING_EXCEPTION_ERROR_NUMBER, new String[] { jndiName });
                                }
                            }
                            public static Object lookupEJB3(String jndiName) throws CustomException {
                                return lookupEJB3(getInitialContext(), jndiName);
                            }
                            
                            public static Object lookupEJB3(Context context, String jndiName) throws CustomException {
                                try {
                                    return context.lookup(jndiName);
                                } catch(NamingException namingException) {
                                    throw new CustomException(NAMING_EXCEPTION_ERROR_NUMBER, new String[] { jndiName });
                                }
                            }
                            
                        }
                        
                        

                         

                        As you are aware, I deploy the WARs on Tomcat and EJBs on another machine with JBoss. The above listed ServiceLocator class is available to the WARs and EJBs and uses separate copies of config files to read initial context properties. All the requests from the UI are channeled through a RequestDispatcherBean which then validates the request and further invokes other business EJBs within the same request.

                         

                         

                        Now, for any request first RequestDispatcherBean is looked up. This is only successful if I set “java.naming.provider.url” to “jnp://192.168.0.1:1099,192.168.0.2:1099” in config file referenced by the WAR; however the look up fails if the value is “jnp://192.168.0.1:1100,192.168.0.2:1100” (CommunicationException). Continuing with the same request, when RequestDispatcherBean invokes the business EJB, its lookup is successful for “java.naming.provider.url” set to “jnp://192.168.0.1:1100,192.168.0.2:1100”. The value “jnp://192.168.0.1:1100,192.168.0.2:1100” is only set in the config file referenced by the EJBs listed in the JBoss AS.

                         

                         

                        I have again restared the servers, and this time “java.naming.provider.url” was set to “jnp://192.168.0.1:1100,192.168.0.2:1100” across configs on different servers. It works.

                         

                        Please advice if the service locator needs any modification and if load-balancing will be possible.

                         

                         

                        Regards,

                        Nitin

                        • 9. Re: JNDI Lookup in JBoss Cluster
                          wdfink

                          Ok, that is what I've supposed.

                          You do every time a nw lookup, this avoid that the remote-proxy will to its job and loadbalace.

                          If you get an object from lookup cache it and reuse it, it is thread save.

                          Than you will get the behaviour that you expect.

                           

                          BTW, with EJB3 you did not need the narrowing, a simple cast is possible.

                          • 10. Re: JNDI Lookup in JBoss Cluster
                            nitin_jain

                            What do you think about the following?

                             

                             

                                final private static String CACHE_TYPE_FOR_SERVICE_LOCATOR = "ejb.ejbhost.servicelocator.cache.type";
                                /**
                                 * get instance of cache from factory given cache type
                                 */
                                private static Cache cache = getCache(CACHE_TYPE_FOR_SERVICE_LOCATOR);
                                public static Object lookupEJB3(Context context, String jndiName) throws CustomException {
                                    try {
                                        Object obj = cache.getFromCache(jndiName);
                                        if (obj == null) {
                                            synchronized (ServiceLocator.class) {
                                                obj = context.lookup(jndiName);
                                            }
                                            cache.putInCache(jndiName, obj, 0);
                                        }
                                        return obj;
                                    } catch(NamingException namingException) {
                                        throw new CustomException(NAMING_EXCEPTION_ERROR_NUMBER, new String[] { jndiName });
                                    }        
                                }
                            
                            

                             

                            What will happen if one node (suppose 192.168.0.1) is abruptly unavailable? I did try the above code; however it failed when node 1 went down as the cache was still holding the node 1 objects.

                             

                            Regards,

                            Nitin

                            • 11. Re: JNDI Lookup in JBoss Cluster
                              wdfink

                              I suppose the Cache and ServiceLocator are implemented well.

                              This aproach should work. The sync-block might be not necesarry because the assignment should be atomar and it doesn't matter if you run it twice.

                               

                              But nevertheless you should see that your calls are loadbalanced if you run with this class..

                               

                              If the 'initial' node crash the proxy should work if the second node is in the same cluster and reachable from the client side. You might activeate logging for 'org.jboss' at the client to see what happen (e.g. which server addresses are used).

                              Also you might show the content of the proxy in your log.

                              • 12. Re: JNDI Lookup in JBoss Cluster
                                nitin_jain

                                When JNDI caching is introduced in the service locator class and a node goes down. Any lookups related to the inactive node fails. However, when I restart the node, the lookups are successful.

                                 

                                Regards,

                                Nitin

                                • 13. Re: JNDI Lookup in JBoss Cluster
                                  wdfink

                                  So I suppose you got it working and you have answers to your questions, right.

                                  • 14. Re: JNDI Lookup in JBoss Cluster
                                    nitin_jain

                                    My original query was related to JNDI lookup failure through NLB cluster setup. As per you advice, I have removed the NLB, and incorporated HA-JNDI, that as per JBoss documentation will provide load balancing of EJB calls, transparent failover, state replication.  (http://docs.jboss.org/jbossas/docs/Server_Configuration_Guide/4/html/clustering-jndi.html)

                                     

                                    During our discussion, you advised to use port 1100 rather that 1099 to actually incorporate HA. The JNDI lookup used to work for ports 1099; however it failed for 1100. The reason for this issue was that the web server (Tomcat) was missing the following jars.

                                     

                                    Missing Jars

                                    jbossha.jar

                                    jboss-ha-client.jar

                                    jboss.jar

                                     

                                    I only realized this error while referring to this http://community.jboss.org/thread/120695 post.

                                     

                                    The last issue that is to be resolved is related to the JNDI lookup failure when caching is introduced in the service locator because the cache holds a reference to the object that is now not available (related node AS shutdown). As per the JBoss documentation (refer the first url in this post),

                                     

                                    “If an EJB is not configured as clustered, looking up the EJB via HA-JNDI does not somehow 
                                    result in the addition of clustering capabilities (load balancing of EJB calls, transparent 
                                     failover, state replication) to the EJB” 

                                    I am afraid but all my EJB beans are missing “@Clustered”. So is this the reason why the lookup has failed in the scenario when the cached object references to an unavailable node and the current lookup is not performed on any other available node?

                                     

                                    Regards,

                                    Nitin

                                    1 2 Previous Next