Tag Archive | jboss-ejb-client

JNDI load balancing with jboss-ejb-client on JBoss AS 7

Let’s assume we have a client application that accesses a remote stateful session bean (SFSB) on a JBoss Application Server AS 7. The SFSB is accessed via JNDI lookup as described here: EJB invocations via JNDI. The SFSB is clustered via the @Clustered annotation as described here: Clustered EJBs.

@Stateful
@Clustered
@Remote(TestRemote.class)
public class TestBean implements TestRemote {
...
}

Note that the infinispan cache used to cluster the SFSB is only started, when during the deployment one SFSB with the @Clustered annotation is found. If we want to start two JBoss servers on the same machine, we can do this with the following command line invocations:

standalone.bat -c standalone-ha.xml -Djboss.node.name=nodeA -b 127.0.0.1
standalone.bat -c standalone-ha.xml -Djboss.socket.binding.port-offset=100 -Djboss.node.name=nodeB -b 127.0.0.1

It is important to note, that both servers have to be bind to a specific ip address. If you bind both server with the option “-b 0.0.0.0” the clustering doesn’t start (see here). Both servers also do have to have a different node name.

The client uses the following properties file to access the SFSB via JNDI:

remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
invocation.timeout=10000
remote.connections=default

remote.connection.default.host=127.0.0.1
remote.connection.default.port=4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false

remote.clusters=ejb
remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false
remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false

Two things are important. First of all we only have to define one of the two servers (here 127.0.0.1:4447). The other server is detected automatically via a topology message that the client receives after he has connected to the first server. It is also important to mention that this topology information is received with some latency, thus if you try to lookup all your SFSBs directly after the first lookup, your client program could be to fast to integrate the information about the second server and therefore all SFSB are executed on the first server. The name of the cluster has also to be defined (here with the property remote.clusters). Then for each defined cluster (here ejb) the SASL_POLICY as well as the SSL configuration is given.

If you now look up the remote bean with the following code, all invocations are load balanced to both server instances:

	private TestRemote lookupRemoteBean() throws NamingException {
		logger.info("Using jboss-ejb-client.");
		final Hashtable<String, String> jndiProperties = new Hashtable<String, String>();
		jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
		final Context context = new InitialContext(jndiProperties);
		final String appName = "jboss-ejb-client";
		final String moduleName = "server-ejb";
		final String distinctName = "";
		final String beanName = TestBean.class.getSimpleName();
		final String viewClassName = TestRemote.class.getName();
		String lookupString = "ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!"
				+ viewClassName + "?stateful";
		logger.debug(String.format("Looking up: %s", lookupString));
		return (TestRemote) context.lookup(lookupString);
	}

The appName and moduleName are chosen as described here.

There is also one more caveat: You can set a selector for the EJB client context to use programmatically:

final EJBClientConfiguration ejbClientConfiguration = new PropertiesBasedEJBClientConfiguration(
				clientConfigProps);
final ContextSelector<EJBClientContext> ejbClientContextSelector = new ConfigBasedEJBClientContextSelector(
				ejbClientConfiguration);
EJBClientContext.setSelector(ejbClientContextSelector);

Here the properties object clientConfigProps is created dynamically during runtime and contains in our example the same information as the properties file from above. If you set this selector directly before each lookup, the topology information is requested again and arrives too late, due to the latency mentioned before. Therefore again all clients are executed on the first server.