Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples

EJB 2 Clustering Stateless Session Beans


"Holy scalability, Batman! How are we going to get the BatWeb to support 100,000 concurrent Gothamites using our patented BatEJB technology? Our BatWeb is primarily built with stateless session BatEJBs on a single BatServer and now you them to work on our BatCluster? Will this work?!?"

Well, Robin, of course it will. There are several architectures that application server vendors can use to make your session beans more scalable and more fault tolerant. In my previous article, EJB 2 Clustering with Application Servers, I talked about the generic approaches that a vendor can use to load balance and cluster EJBs, focusing on the importance of load balancing and fail over logic contained directly within the home and remote stubs downloaded to a remote client. This article will expand upon that approach for stateless session EJBs by demonstrating additional load balancing and fail over techniques.

Load Balancing

The first enhancement that application server vendors can implement is load balancing of client invocations to EJBs in different servers or different virtual machines. (See Figure 1: Big Picture of Stateless Session Beans.) Since all instances of a stateless session bean type are identical, a home or remote stub can have its request serviced by any available object on any server. The remote stub doesn't care whether an instance in the first or the second server handles the request, as long as the request gets handled.

Figure 1: Big Picture of Stateless Session Beans.

Figure 1: Big Picture of Stateless Session Beans.

Application servers can scale if they're configured such that home stubs and remote stubs balance the load of method invocations across servers. Each method call handled by a stub would execute a ServerChooser algorithm in the stub to select which server is best suited for handling this method invocation. The ServerChooser would return the IP address or connection to the server that best meets the criteria needed for this method invocation. Then the stub forwards the invocation to that server.

Since all stateless session EJBs are identical, the home and remote stubs can select, with some flexibility, the server to handle particular requests. Popular types of balancing algorithms in use today include the five following.

Fault Tolerance

Load balancing sounds easy to incorporate, doesn't it? Well, for the most part, it is. However, incorporating fault tolerance and fail over into your EJB applications is more complicated. There are many issues involved in accomplishing a successful fail over (and to supporing fault tolerance).

  1. How does a home or remote stub determine whether a failure situation has occurred? If an exception is generated, how does a stub know that the exception is a failure condition that cannot be recovered? There are three types of exceptions that a stub can receive: application exceptions (those defined by the bean developer), system exceptions (typically in the form of EJBException), and network/communication exceptions. Application and system exceptions are clearly defined in the EJB specification and are typically propagated to the invoking client to be handled. Network/communication exceptions, such as SocketException, CommunicationException, and others, indicate a much more dire, unable-to-communicate-with-server scenario. An application server stub can intercept all system and communication exceptions and may perform a fail over to another server, if it's safe to do so. Why wouldn't it be safe?

  2. At what point in the invocation did the failure occur? There are three situations to consider.

    1. The failure occurred before the server-side invocation started. If the stub can determine that a failure occurred after the method request was sent but before it was invoked on the server, the stub can treat this failure as a load balance scenario and re-direct the method invocation to any other available server.
    2. The failure occurred after the server-side invocation completed, but before the response message was properly propagated to the client. This situation doesn't require any further action from the stub.
    3. The failure occurred during the server-side invocation. The method that was invoked on the server may or may not have altered some server-side resources that impact future behavior of the system. If the stub makes a subsequent request on a method that impacts server-side resources or data, the stub may inadvertently perform the same altering action twice in a row during a failure recovery, thus causing the system to behave indeterminately. If the method doesn't perform any of these altering actions, then it could safely invoke the method again. But if it does alter the system, it cannot.

    Unfortunately, even though the (a) and (b) scenarios have a very happy ending, it is difficult to determine for certain which state the system is in. As a result, a stub will likely have to assume that if a failure situation occurs, the server was in (c), the worst-case scenario, even if in fact it was in (a) or (b).

So should the application server do? Many application servers support idempotent methods, which yield the same results on subsequent invocations if the same input arguments are provided. A non-idempotent method alters the state of the system (that is, yields different results) on subsequent executions. Types of methods that are idempotent include

As a bean developer you are aware of the behavior of the methods you. Using the utilities provided by the vendor, you specify the idempotent and non-idempotent bean methods. At runtime, an application server that encounters a failure situation during a method invocation can freely perform a fail over switch if the method that was being executed is idempotent. After all, if the method doesn't alter the state of the system, then the stub may assume the existing system is intact and that a new invocation will not have odd side effects. In situations where a failure occurs on a method that is not idempotent, the stub will be forced to throw the communication exception it receives to the client. Your client application will have to determine whether it should try another invocation or not.

try {
MyHome home = (MyHome) ctx.lookup("MyEJB");

// This should use PortableRemoteObject.narrow().
My remote = (My) home.create();

} catch (javax.naming.CommunicationException exception) {

// This is a type of Naming Exception
// This is an acceptable exception for me. Calling this method again
// will not adversely impact the system.

try {
} catch (java.io.IOException exception) {

// This must be some sort of socket exception.
// I don't want to call this method again, so now it must be
// handled in another way that you determine!



As you can see, a variety of options exist for smoothly integrate stateless session EJBs in clustered implementations. Obviously I have not addressed stateful session beans. Statefulness adds another level of complexity since stateful bean stubs are "pinned" to the object that they represent. This reduces load balance and fail over flexibility, but they may still be done. How they are done is the topic of the next article in this clustering series. Until then, good luck and happy scaling!

Tyler Jewell , Director, Technical Evangelism, BEA Systems Tyler oversees BEA's technology evangelism efforts that are focused on driving early adoption of strategic BEA technologies into the ISV and developer community.

Read more EJB 2 columns.

Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.