ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

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.

  • Random -- A seed-based, random selection of a server to handle a request; may incorporate statistical irregularities over the short term.

  • Round Robin -- Sends requests to different servers in a statistically regular way.

  • Weighted Round Robin -- A derivative of round robin, it favors certain servers using ratios. Administrators and developers apply relative weights to different servers that determine how much of the load they should handle. One design pattern is to set the weight of a server that needs some maintenance to zero, thus eliminating any EJB traffic to that server.

  • High Availability - A derivative of the round-robin algorithm, it "pins" a stub to a single server until the server can no longer handle the request, at which time the stub makes a "high availability" switch to the next server (which is typically done in a round-robin fashion).

  • Programmatic - In some application servers you can write your own stub-based balancing algorithm as a Java class compiled into the stub implementation. The class that you implement typically has a single method that is executed whenever a remote or home stub has to select a server. The method that you implement will typically have access to reflection method and input arguments that relate to the method that the client invoked. From this information, the method generates a list of servers or IP addresses of servers to try when the stub needs to load balance. The order of this list dictates the order of the balancing scheme applied by the stub. This is a great way to implement a staging, test, and production environment for your EJBs. Depending upon the values of the input parameters or the current value of a flag specified in a text file, your programmatic filter can alter requests to different servers depending upon whether you are testing an application or running it in production mode.

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

  • any method that acts as a "reader / getter" method,
  • any method that performs a non-altering query, and
  • any method that accesses a resource manager, but leaves the state of the resource manager unaltered.

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.