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


AddThis Social Bookmark Button

Clustering with Tomcat
Pages: 1, 2, 3

Our Solution

Typical clustering solutions use a client-server paradigm to implement a distributed system as a solution, but they have limited scalability.

In the space paradigm that is used here, a request is fulfilled by having an object move from one machine to another, carrying with it the present state of execution and everything else needed, including the (byte)code, if needed, using an associative, distributed, shared memory.

Let us examine how the Jakarta Tomcat Servlet engine works. It uses a connector and a processor to receive and fulfill requests, as shown in Figure 2.

Figure 2. Architecture of a Stand-alone Tomcat Servlet Engine

The connectors abstract the details of receiving the request from different sources, while the processor abstracts the details of fulfilling the requests.

Figure 3 below shows the architecture of our proposed clustering solution.

Figure 3. Architecture of the Clustered Tomcat Servlet Engine

The Cluster Server Connector receives the requests from the clients, and the Cluster Server Processor encapsulates the requests into RequstEntry objects and writes them into the JavaSpace. The Cluster Worker Connector then takes these requests from the JavaSpace and the Cluster Worker Processor then fulfills the request.

There can be multiple instances of these Cluster Servers and Cluster Workers, and they can be distributed across a number of machines.

The RequestEntry is defined as follows:

public class RequestEntry extends 
      net.jini.entry.AbstractEntry {
  private static int ID = 0;
  public RequestEntry(){
    id = String.valueOf(ID++);
  public String id;
  public RemoteSocketInputStream input;
  public RemoteOutputStream output;

The id field identifies a request. The input field is an object of type RemoteSocketInputStream that provides access to the input stream of a socket on a remote machine, and the output field is of type RemoteOutputStream that provides access to a remote output stream.

When a request is received, the socket's input and output streams are wrapped with the remote stream implementations that make them accessible from a remote machine. A request entry is created with these remote streams and written into the JavaSpace by the Cluster Server Processor as in the code below:


* Process an incoming HTTP request on the Socket that has been assigned
* to this Processor. Any exceptions that occur during processing must be
* swallowed and dealt with.
* @param socket The socket on which we are connected to the client

private void process(Socket socket) {
  RemoteSocketInputStream input = null;
  RemoteOutputStream output = null;
    //had to synchronize because of a threading problem with the TC class loader
      input = new RemoteSocketInputStreamImpl(socket, connector.getPort());
      output = new RemoteOutputStreamImpl(socket.getOutputStream());
    log("socket address = " + input.getSocketAddress() + 
    ", port " + input.getServerPort());
    RequestEntry entry = new RequestEntry();
    entry.input = input;
    entry.output = output;
  }catch(Exception ex){
  log("parse.request", ex);


The Cluster Worker Connectors/Processors then take these entries and fulfill the requests, as shown in the code below:

public void run() {
  //process requests until we receive a shutdown signal
  while (!stopped) {
    log("waiting for entry in JavaSpace...");
    RequestEntry requestEntry = null;
      requestEntry = (RequestEntry)requestReader.take();
    }catch(Exception ex){
      log("internal error while getting request entry from JavaSpace", ex);
    log("got an entry " + requestEntry);
    // process the request
    if (requestEntry != null)

Pages: 1, 2, 3

Next Pagearrow