Cluster-enabling servlet application in Weblogic Setup



Weblogic Clustering

This is really nothing new - it is well-documented on the BEA websites. However, I decided just to give it a quick run-through anyway - with a sample application, which I'll be using in other examples.

As you're probably aware, cluster-eabling of application mainly introduces following advantages: Far too rare is actually used clustering - and it's a shame since it's fairly simple (that is... if you disregard the costs of an application server cluster license). This exaple will introduce a simple cluster with a demonstration servlet, running on a single machine (binding to a single ip-number) using in-memory state replication and demonstrating the fail-over in a clustered environment - since this is usuably one of the most important motives for introducing a cluster.

There are a number of different ways of implementing session persistence. The method is specified in:

META-INF/weblogic.xml
weblogic.xml

<session-descriptor>
 <session-param>
  <param-name>PersistentStoreType</param-name>
  <param-value>...</param-value>
 </session-param>
</session-descriptor>

A condition for successfull failover using in-memory state replication is having your servlet application using the HttpSession object to keep state information related to the client connection. If that's the case, it's possibly to quickly apply a cluster setup.

Here will be described a roadmap to quickly get a demonstration running.

Configuring a cluster

  1. In the left pane, click the Clusters node.

  2. In the right pane, click Configure a New Cluster.
  3. Enter values for:
  4. Click Create to create the cluster.
  5. Click the Multicast tab.
  6. If necessary (not now!), edit the default values for:
  7. Click Apply.
  8. In the right pane, click the Servers tab.
  9. In the Available column, select one or more servers to assign to the cluster (not now!).
  10. Click the right arrow button.
  11. Click Apply.

Configuring two servers for the cluster

  1. In the right pane, right-click on the Servers node
  2. Select "Configure a new Server"
  3. Enter values for:
  4. Click Apply.

Same story for the other server:
  1. Right-click on the Servers node...
  2. Select "Configure..."
  3. Enter values for:
  4. Click Apply.


Configure a proxy

There exists different proxy alternatives such as an additional Weblogic server acting as proxy (HttpClusterServlet deployes and enabling proxy functionality). In general there are proxy alternatices: First define a regular Weblogic server just as any other managed server used to host applications. Using the console:



Define name (TopsecurityProxy, ip and port to operate from...)




Next, deploy the servlet "HttpClusterServlet" on the proxy server. The classes for the servlet is contained in "weblogic.jar" and already in global weblogic classpath. So you only need to worry about deployment descriptors:


WEB-INF/web.xml
web.xml


<!DOCTYPE web-app PUBLIC 
  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
  "http://java.sun.com/dtd/web-app_2_3.dtd">
  
<web-app>

  <servlet>
    <servlet-name>HttpClusterServlet</servlet-name>
    <servlet-class>weblogic.servlet.proxy.HttpClusterServlet</servlet-class>

    <init-param>        
      <param-name>WebLogicCluster</param-name>        
      <param-value>127.0.0.1:8001|127.0.0.1:9001</param-value>     
    </init-param>
    
    <init-param>
      <param-name>verbose</param-name> 
      <param-value>true</param-value> 
    </init-param>
  
    <init-param>        
      <param-name>DebugConfigInfo</param-name>        
      <param-value>ON</param-value>     
    </init-param>
  </servlet>
  
  <servlet-mapping>    
    <servlet-name>HttpClusterServlet</servlet-name>    
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  
  <servlet-mapping>    
    <servlet-name>HttpClusterServlet</servlet-name>     
    <url-pattern>*</url-pattern> 
  </servlet-mapping>
  
</web-app>


WEB-INF/weblogic.xml
weblogic.xml

<!DOCTYPE weblogic-web-app PUBLIC "-//BEA
Systems, Inc.//DTD Web Application 8.1//EN"
"http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">

<weblogic-web-app>
  <context-root>/</context-root>
</weblogic-web-app>


which you pack into a file "HttpClusterServletProxy.war" and put somewhere, from where you deploy to the server "TopsecurityProxy" just defined previously.




Deploy on the server just defined...




No need to distribute by copying file... Will only be deployed one place - might just as well use the same .war file just packed.




The running state of the servlet depends on if the server is already running - which is not the case here. "Deferred" just means the .war file application will be activated once the "TopsecurityProxy" server gets started.




So don't worry if the servlet hasn't startws - we'll take care of that next!




Start Cluster & proxy (everything)

For simplification we'll not use the node manager. It is furthermore assumed you already have the administration console running, since you have just been using the console.

And the "HttpClusterServletProxy" should be deployed by now:



Monitoring a Cluster

The Cluster-->Monitoring page displays current status of the cluster, and statistics on the activity of each Managed server in the cluster.

  1. In the left pane, expand Clusters.
  2. Click a cluster name that you want to monitor.
  3. In the right pane, click the Monitoring tab.
  4. The Monitoring page displays the number of servers configured for the cluster, the number of servers currently participating in the cluster, and in tabular form, key statistics on each Managed Server's recent activity.


The application

The application consist of the program "TopsecurityTimeServlet.class" and a couple of deployment descriptors (web.xml and weblogic.xml).


WEB-INF/classes/dk/topsecurity/TopsecurityTimeServlet.class
TopsecurityTimeServlet.java

package dk.topsecurity;

import java.util.*;
import java.io.*;
import java.text.*;
import javax.servlet.*;
import javax.servlet.http.*;

import javax.naming.Context;
import javax.naming.InitialContext;
import weblogic.management.MBeanHome;

import javax.servlet.http.HttpSession;
//http://dev.w3.org/cvsweb/java/classes/org/w3c/jigsaw/servlet/JigsawHttpSession.java?rev=1.6.4.4

public class TopsecurityTimeServlet extends HttpServlet
{

   int timesThisCalled = 0;
   String heading = null;
   ServletConfig servletConfig = null;

   public TopsecurityTimeServlet() { }

   public void init(ServletConfig config) throws ServletException {
       super.init(config);
       servletConfig = config;
       heading = config.getInitParameter("topsecurity_servlet_version");
       System.out.println(heading+" init method ok.");
   }

   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       handleRequest(request, response);
   }

   protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       handleRequest(request, response);
   }


  private String getServerName() throws Exception {
    String toReturn = null;
    try {
      Context myCtx = new InitialContext();
      MBeanHome mbeanHome = (MBeanHome)myCtx.lookup("weblogic.management.home.localhome");
      toReturn=mbeanHome.getMBeanServer().getServerName();
      if (toReturn == null) return "";
      else return toReturn;
    }
    catch (Exception e) {
      throw e;
    }
  }



   private void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       try {
           Integer timesCalledNew;
           HttpSession session = request.getSession();
           Integer timesCalled = (Integer)session.getAttribute("timesCalled");
           timesCalledNew = timesCalled==null ? new Integer(1) : new Integer( 1+timesCalled.intValue());
           session.setAttribute("timesCalled", timesCalledNew);
           timesThisCalled++;

           Calendar calendar = new GregorianCalendar();
           Date date = calendar.getTime();
           String timeStr = (new SimpleDateFormat( "yyyy.MM.dd hh:mm:ss" )).format( date );


           PrintStream out = new PrintStream(response.getOutputStream());
           out.print("<html><head><title>"+heading+"</title></head><body>");
           out.print("Servlet: " + heading + "<br>");
           out.print("Running from: " + getServerName() + "<br>");
           out.print("Registered time: " + timeStr + "<br>");
           out.print("Time(s) called this server : " + timesThisCalled + " times<br>");
           out.print("Time(s) called on cluster : " + timesCalledNew.intValue() + " times<br>");
           out.flush();
       }
       catch(Exception ex) {
           System.err.println("Topsecurity TimeServlet got Exception: " +
           ex.toString());
           ex.printStackTrace();
       }
   }
}



And deployment descriptors:


WEB-INF/web.xml
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

 <display-name>Topseurity Time Servlet</display-name>

   <context-param>
           <param-name>environment</param-name>
           <param-value>production</param-value>
   </context-param>

   <servlet>
           <servlet-name>TopsecurityTime</servlet-name>
           <servlet-class>dk.topsecurity.TopsecurityTimeServlet</servlet-class>
           <init-param>        
              <param-name>topsecurity_servlet_version</param-name>        
              <param-value>Topsecurity Time Servlet version 1.0 /2006-6-22</param-value>    
           </init-param>
   </servlet>

   <session-descriptor> 
      <session-param> 
         <param-name>TimeoutSecs</param-name> 
         <param-value>3600</param-value> 
      </session-param> 
   </session-descriptor> 

   <servlet-mapping>
           <servlet-name>TopsecurityTime</servlet-name>
           <url-pattern>*</url-pattern>
   </servlet-mapping>

</web-app>



and


WEB-INF/weblogic.xml
weblogic.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN"
 "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">

<weblogic-web-app>

     <context-root>/toptime</context-root>

     <session-descriptor>
      <session-param>
       <param-name>PersistentStoreType</param-name>
       <param-value>replicated</param-value>
      </session-param>
     </session-descriptor>

</weblogic-web-app>



Assemble: compile... pack... to "toptime.war"

Then assemble "toptime-ear.ear" with additional deployment descriptor


META-INF/application.xml
application.xml

<?xml version="1.0"  encoding="UTF-8"?>

<!DOCTYPE application PUBLIC '-//Sun Microsystems, Inc.//DTD J2EE Application 1.2//EN' 'http://java.sun.com/j2ee/dtds/application_1_2.dtd'>

<application>
  <display-name>webservice1</display-name>
  <description>An archived ear containing an archived war</description>
  <module>
     <web>
       <web-uri>toptime.war</web-uri>
       <context-root>/toptime</context-root>
     </web>
  </module>
  
</application>

We deploy the application:












The application should now be accessible from:

Demonstrating failover

Calling the servlet application through the proxy reveals that the proxy (in this case) starts on node2.




As the servlet clearly states, the servlet has just been instantiated and the called number of times is identical for the instantiated servlet as well as for the cluster overall.



...all the way up to a substantial number of times.



Then is decided to stop TopsecurityNode2 (which has been servicing all previous requests - thereby simulating a service breakdown). The cluster monitoring confirms that the server has actually been stopped.



This has immediate effect on the cluster, which transfer the present state to node1, which subsequently continue to services further requests. The state replicated here is the cluster-request-counter - but it could basicly be any other serializable object.



The servlet on node1 continues responding until session is terminated with the client.



/topsecurity.dk 2006-7-6