Skip to main content
Jump to: navigation, search

RAP/RWT Cluster

Revision as of 07:57, 26 July 2011 by (Talk | contribs) (Configuration)

| RAP wiki home | RAP project home |

Support for Transparent Session Failover in RWT is work in progress and details outlined below may change without prior notice


Load balancing to distribute workload across multiple nodes in a cluster works with RAP out of the box since version 1.0. One thing to mind though when setting up a load balancer for RAP applications is that it must be configured to use sticky sessoins (aka session affinity). This entails that once a session is started, the same server serves all subsequent requests for that session. For information on how to set up load balancing, refer to the servlet container documentation. E.g. Tomcat

If your application provides critical servies you may want to make it fail safe by running it in a high high-availability cluster. A high availability cluster operates by having redundant nodes. So that if one node crashes, the service as a whole is unafected as other nodes take over the work.

Transparent Session Failover

With version 1.5 M1, RAP can be configured for transparent session failover so that applications can run in a high-availability cluster. This means that two or more servlet engines form a cluster, where a session, and its contents, can be moved from one node of the cluster to another node.

In §7.7.2 (Distributed Environments), the servlet specification requests for distributable aplications that all session data must implement the Serializable interface. This results in two main abstacles to overcome with the current implementation:

  • All RWT objects that live in the session scope (i.e. are directly or indirectly stored in a session attribute) must be serializable. This will mainly affect Display, Widget and derived classes and Resource and derived classes.
  • The RWTLifeCycle which creates a UI Thread that lives until the session is terminated. The UI thread is necessary to enable blocking dialogs and so ensures compatibility with SWT. The downside of the UI thread of course is that sessions cannot be migrated as - naturally - a thread cannot be serialized.

Serializable RWT sessions can also be used to swap inactive sessions onto disk and thereby releasing the memory consumed by them. This allows for long to infinite session timeout settings that result in user friendly web applications that don't bother users with 'session has expried' messages and on the other hand don't consure more memory than actually needed. This feature is e.g. supported by Tomcat

State of Development

bug 341761 is used as a meta-bug to capture the problem and track the solution. For details, please see the bugs that this bug depends on.

Alternative Life Cycle

An alternative life cycle implementation is availiable that does not use an extra thread. As a consequence thereof blocking dialogs aren't possible with this life cycle. The new life cycle also makes it easier to access security or transaction contexts and is conform to the JEE Specification. Even if you don't have a need for high availability clustering, if you don’t use blocking dialogs or workbench features we recommend to use this life cycle.

For application code to still be able to use dialogs we introduced the DialogUtil helper class. It allows to open dialogs in a non-blocking way and informs you via the supplied DialogCallback when the dialog was closed.

MessageBox messageBox = new MessageBox( parent, SWT.YES | SWT.NO );
messageBox.setMessage( "Are you OK?" ); messageBox, new DialogCallback() {
  public void dialogClosed( int returnCode ) {
    if( returnCode == SWT.YES ) {
      // ...
} );

Please consult the JavaDoc for further details.

UICallback#activate() and #deactivate() are not affected by this life cycle. They continue to work as with the UI-threaded life cycle. However, UICallback#activate() is usually used to propagate changes from background threads to the UI. We need to investigate if it is feasible to use background threads (with certain constraints) in a high availability environment.

Serializable Session Data

The core classes with session scope are serializable. This includes Device and Display, all widgets, layouts and layout data, Dialog and its subclasses, Accessible and its associated classes, drag & drop classes, resources, data structures (e.g.Point, Rectangle, etc.), listeners and their respective events, ISessionStoreListener.

If a session attribute changes, the servlet engine must be told to replicate the change. Unfortunately the Servlet specs do not specify how this should be done. The most common way is to call HttpSession.setAttribute() to flag the object as changed (see J2EE clustering, Part 2, section Session-storage guidelines). In RWT, after each request the session attribute that holds the ISessionStore is re-set into the session. This means that as long as application code stores data in an attribute of the ISessionStore or with the help of SessionSingletonBase, all changes will be replicated.

Known Limitations

  • Images that were created with one of the Graphics#getImage() methods (curently) cannot be serialized (bug 352929).
  • The graphics context (GC) is not meant to be serialized because it should only be used within the scope of a request. I.e. it is created and ddestroyed within the paintControl() method of a PaintListener.
  • As a consequence of the threadless life cycle, Display#sleep() cannot be implemented and throws an UnsupportedOperationException.
  • Because of the missing Display#sleep(), Browser#execute() and evaluate() will not work either. These methods call sleep() to wait for the result of the Javascript execution.
  • A further consequence of the missing Display#sleep() is of course that entry points must not contain the usual event loop (see below for an example).

Test Infrastructure

To be able to run tests from JUnit, there are helper classes with which an arbitrary number of embedded serlvet engines can be created. Either standalone or clustered. Currently the tests can be run with Jetty 7.4 and Tomcat 7.

The tests reside the source code repository under org.eclipse.rap.rwt.cluster.test and the fixture can be found in org.eclipse.rap.rwt.cluster.testfixture. Tests for the fixture in turn are in org.eclipse.rap.rwt.cluster.testfixture.test.


In order to run an RWT application in a cluster configuration, an additional servlet filter must be registered. The web.xml should look like the one below:

  <?xml version="1.0" encoding="UTF-8"?>
  <web-app version="2.4" 
      <param-value> the class name of your entry point goes here </param-value>

In addition the threadless life cycle must be selected. To do so, set the lifecycle system property to org.eclipse.rwt.internal.lifecycle.SimpleLifeCycle. The means to configure RWT to use this life cycle will change with the ongoing work on bug 347883 As this life cycle does not support Display#sleep(), the readAndDispatch loop must be removed from the entry point. Make your entry point look like the one below.

public class SimpleEntryPoint implements IEntryPoint {
  public int createUI() {
    Display display = Display.getDefault();
    Shell shell = new Shell( display );
    shell.setBounds( 10, 10, 850, 600 );
    shell.setText( "Hello World" );
    // create more widgets...;
    // omit the event loop
    return 0;

If the application is going to use Display#(a)syncExec() to propagate UI changes from background threads, an appropriate Synchronizer must be attached to the Display.

  Display display = Display.getDefault();
  display.setSynchronizer( new ClusteredSynchronizer( display ) );

Performance Comparison

To get an idea what the performance impact of clustering a web application means, we did a basic load tests.

A simple web application that consists of a shell and several buttons was used. This application was deployed to a Tomcat 7.0 and a Jetty 7.4 servlet engine. Each once configured as a single engine and once clustered.

With the help of JMeter, a web session was recorded in which several of the buttons were selected. The entire recording consists of 24 requests. This session was then played back, simulating 500 concurrent users with a ramp up period of 60 Seconds that use the web application.

Even though the performance impact is significant, the response times are sufficiently fast for Ajax-driven web applications Manual sessions that were opened while the load tests were running, also proved that. The table below shows the response times for each of the scenarios in Milliseconds.

Average Median 90% Line
Jetty single 4.8 ms 1 ms 4 ms
Jetty cluster 13.3 ms 6 ms 29 ms
Tomcat single 1.5 ms 1 ms 2 ms
Tomcat cluster 3.1 ms 2 ms 6 ms

Performance comparison between single and clustered servlet engines

Development Snapshots

Development takes place in HEAD, if you are interested you may want to directly check out from the source code repository. Nightly builds are also available and can be obtained from the downloads page.

If you whish to run the cluster tests, you will have to add the Jetty 7.4, the H2 database (version 1.1) and the Servlet API (version 3.0) to your target platform. The Eclipse Orbit project offers bundled versions of H2 (org.h2) and the Servlet API (javax.servlet). In addition Tomcat 7.0.12 is needed, please use the pre-bundled version from the RAP source code repository at /cvsroot/rt/org.eclipse.rap/runtime.rwt.test.

Please note that these tests (like all other RWT tests) are neither part of nightly builds nor milestone builds.


We plan to ship the first version with milestone 1 of RAP 1.5 which will be available end of August 2011. The exact date depends on the Juno/Simultaneous Release Plan.

Back to the top