4 Replies Latest reply on Jan 23, 2008 9:53 AM by azheludkov

    Load-balancing is not happening in cluster

    azheludkov

      Does anybody know why stateless EJB is executed always on the node where client resides and is never load balanced?

      I have successfully configured a two-node JBoss cluster, and deployed an EJB module to the cluster. When running the test client to invoke the EJB, all requests are always serviced by node 1 (where ejb client resides), never by node 2.

      Here is another interesting detail. When client runs from outside of JBoss as stand-alone application and submits requests to JBoss cluster, the cluster routes requests to different nodes. I mean load-balancing works.
      Another factor in my application is, client invokes the ejb from inside JBoss.
      On the JBoss forum http://www.jboss.com/index.html?module=bb&op=viewtopic&t=112500
      I found something similar to my problem, but I gess it only works for ejb 3.x, not ejb 2.x

      Here are configuration details:
      - JBoss 4.2.2-GA;
      - EJB client runs inside of JBoss container;
      - SLSB 2;
      - JNDI properties:
      java.naming.provider.url = jnp://localhost:1100
      java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
      java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
      jnp.partitionName=DefaultPartition

      - jboss.xml:

      <enterprise-beans>

      <ejb-name>SubmitterBean</ejb-name>
      <jndi-name>Submitter</jndi-name>
      true
      <cluster-config>
      <partition-name>DefaultPartition</partition-name>
      <home-load-balance-policy>
      org.jboss.ha.framework.interfaces.RoundRobin
      </home-load-balance-policy>
      <bean-load-balance-policy>
      org.jboss.ha.framework.interfaces.RoundRobin
      </bean-load-balance-policy>
      </cluster-config>

      </enterprise-beans>

      My client creates home stub only once and caches it. For every ejb invocation a new remote interface stub is created.
      In client class constructor I create home stab only once and cache it as a member variable:

      Properties props = new Properties();
      prop.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory")
      . . .
      See all properties above.
      . . .
      Context ctx = new InitialContext(jndiProperties);
      Object obj = ctx.lookup(lookupName);
      m_home = (SubmitterHome) javax.rmi.PortableRemoteObject.narrow(obj, SubmitterHome.class);

      But for every EJB invocation I create new remote interface stub, like here:
      Submitter execute = null;
      try {
      execute = (Submitter) m_home.create();
      execute.submitJob(m_jt);
      } catch (Exception ex) {
      ex.printStackTrace();
      }
      }

      Any help would be much appreciated.
      Thanks.

        • 1. Re: Load-balancing is not happening in cluster
          brian.stansberry

          http://wiki.jboss.org/wiki/Wiki.jsp?page=ClusteringFAQ

          "Why are calls between clustered session beans not load balanced even though load balancing policy is Round Robin?"

          • 2. Re: Load-balancing is not happening in cluster
            azheludkov

            Brian thanks for a lead.
            But I still am wondering if it possible to turn off default rerouting from remote to local ejb call without writing custom interceptor. I found in JBoss documentation that it possible by modifying standardjboss.xml file:

            <invoker-proxy-binding>
            clustered-stateless-unified-invoker
            . . . .
            <client-interceptors>

            . . . . .
            <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor
            <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor


            . . . . .
            <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor
            <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor

            </client-interceptors>
            </proxy-factory-config>
            </invoker-proxy-binding>.

            I thought that if I change property call-by-value='false' to 'true' it would work, but I got 'Connection refused' exception. Probably I miss something else or this is completly wrong idea.
            Correct me please if I'm wrong

            • 3. Re: Load-balancing is not happening in cluster
              brian.stansberry

              Using MarshallingInvokerInterceptor will make no difference; the relevant behavior is inherited from superclass InvokerInterceptor.

              • 4. Re: Load-balancing is not happening in cluster
                azheludkov

                Thanks,
                Now load balancing works, but some weird issue occurs from time to time.
                According to FAQ I created my custom InvokerInterceptor and modified standardjboss.xml to replace JBoss's invoker by my custom one.

                When my client makes ejb calls via threads and sometimes I get exceptions like this.

                java.lang.NullPointerException
                at org.jboss.invocation.unified.interfaces.UnifiedInvokerHAProxy.invoke(UnifiedInvokerHAProxy.java:255)
                at org.jboss.invocation.InvokerInterceptor.invokeInvoker(InvokerInterceptor.java:365)
                at org.jboss.invocation.InvokerInterceptor.invoke(InvokerInterceptor.java:197)
                at org.jboss.proxy.ejb.RetryInterceptor.invoke(RetryInterceptor.java:176)
                at org.jboss.proxy.TransactionInterceptor.invoke(TransactionInterceptor.java:61)
                at org.jboss.proxy.SecurityInterceptor.invoke(SecurityInterceptor.java:70)
                at org.jboss.proxy.ejb.StatelessSessionInterceptor.invoke(StatelessSessionInterceptor.java:112)
                at org.jboss.proxy.ClientContainer.invoke(ClientContainer.java:100)
                at $Proxy74.submitJob(Unknown Source)
                at com.framework.system.cluster.ClusterJobSubmitter$RunInThread.run(ClusterJobSubmitter.java:118)
                at java.lang.Thread.run(Thread.java:595)




                It looks like ejb instance fail to connect client on return. Ejb instance did its work on remote sevrver.
                Do you have any idea why?

                Here is a code:
                1. Custom Invoker (Jar with compiled invoker was placed in jboss-4.2.2.GA\server\all\lib ).

                package com.framework.jboss;
                import org.jboss.invocation.*;
                public class CustomInvokerInterceptor extends InvokerInterceptor {
                public boolean hasLocalTarget(Invocation invocation) {
                return false;
                }
                }

                2. Modified piece of standardjboss.xml

                <invoker-proxy-binding>
                clustered-stateless-unified-invoker
                <invoker-mbean>jboss:service=invoker,type=unifiedha</invoker-mbean>
                <proxy-factory>org.jboss.proxy.ejb.ProxyFactoryHA</proxy-factory>
                <proxy-factory-config>
                <client-interceptors>

                org.jboss.proxy.ejb.HomeInterceptor
                org.jboss.proxy.SecurityInterceptor
                org.jboss.proxy.TransactionInterceptor
                org.jboss.proxy.ejb.SingleRetryInterceptor
                <interceptor call-by-value="false">org.jboss.invocation.InvokerInterceptor
                <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor


                org.jboss.proxy.ejb.StatelessSessionInterceptor
                org.jboss.proxy.SecurityInterceptor
                org.jboss.proxy.TransactionInterceptor
                org.jboss.proxy.ejb.SingleRetryInterceptor
                <interceptor call-by-value="false">com.framework.jboss.CustomInvokerInterceptor
                <interceptor call-by-value="true">org.jboss.invocation.MarshallingInvokerInterceptor

                </client-interceptors>
                </proxy-factory-config>
                </invoker-proxy-binding>

                3. Client’s snippet of code:

                public class ClusterJobSubmitter {

                private JobSubmitterHome m_home = null; // ejb home
                . . . . . .
                public void runJob(Ticket jt) throws Exception {
                synchronized (this){
                if (m_home==null) {
                createEjbHome();
                }
                }
                RunInThread runner = new RunInThread(jt);
                Thread thread = new Thread(runner);
                thread.start();
                }

                class RunInThread implements Runnable {
                Ticket m_jt=null;

                public RunInThread(Ticket jt) {
                m_jt= jt;
                }

                public void run() {
                JobSubmitter execute = null; \\ ejb remote stab
                try {
                synchronized (m_home){
                execute = (JobSubmitter) m_home.create();
                }
                execute.submitJob(m_jt);
                } catch (Exception ex) {
                ex.printstacktrace();
                }
                }
                }
                }