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:
- scalability
- load-distribution
- fail-over handling
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>
|
- Memory - single-server, non-replicated (PersistentStoreType="memory")
- File system persistence (PersistentStoreType="file")
- JDBC persistence (PersistentStoreType="jdbc")
- Cookie-based session persistence (PersistentStoreType="cookie")
- In-memory replication across a cluster (PersistentStoreType="replicated")
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
- In the left pane, click the Clusters node.

- In the right pane, click Configure a New Cluster.
- Enter values for:
- Name—assign a unique name to the cluster. Each configurable resource in your WebLogic Server environment should have a unique name.
- Cluster Address—supply a cluster address that identifies the Managed Servers in the cluster. The cluster address is used in entity and stateless beans to construct the host name portion of URLs. If the cluster address is not set, EJB handles may not work properly.
- Default Load Algorithm (round-robin will do fine for a start - you can change it later)
- WebLogic Plug-In Enabled (leave it - needed only when WebLogic plugins are configured)
- Service Age Threshold (leave it at 180 secs)
- Client Cert Proxy Enabled (leave it - no need for HttpClusterServlet to proxy the client certificate in a special header)
- Click Create to create the cluster.
- Click the Multicast tab.
- If necessary (not now!), edit the default values for:
- Multicast Address (use a value between 224.0.0.1 and 239.255.255.255)
- Multicast Port number
- Multicast Send Delay
- Multicast TTL
- Multicast Buffer Size
- Click Apply.
- In the right pane, click the Servers tab.
- In the Available column, select one or more servers to assign to the cluster (not now!).
- Click the right arrow button.
- Click Apply.
Configuring two servers for the cluster
- In the right pane, right-click on the Servers node
- Select "Configure a new Server"

- Enter values for:
- Name—assign a unique name 'TopsecurityServer1' to the server. Each configurable server in your WebLogic Server environment should have a unique name.
- Machine (leave it)
- Cluster (select the cluster we just created - TopsecurityCluster)
- Listen address (ip)
- Listen port Enabled (yes, otherwise server is not reachable)
- Listen port (choose one, which is not already in use by the admin server or the nodemanager, fx. 8001 or 9001)

- Click Apply.
Same story for the other server:
- Right-click on the Servers node...
- Select "Configure..."
- Enter values for:
- Name—assign a unique name 'TopsecurityServer2' to the server. Each configurable server in your WebLogic Server environment should have a unique name.
- Machine
- Cluster - as before...
- Listen address - as before..
- Listen port Enabled...
- Listen port (now choose 9001)

- 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:
- WebLogic Server with the HttpClusterServlet
- Sun One Web Server with the Netscape (proxy) plug-in
- Apache with the Apache Server (proxy) plug-in
- Microsoft Internet Information Server with the Microsoft-IIS (proxy) plug-in
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.
- startWebLogic.cmd - not necessary since admin server probably
already running - additional attempts to start will just result in error messages that
the port is occupied. However the admin server must be started
to the extent "<Thread "ListenThread.Default" listening on port 7001, ip address *.*>"
before trying to start anything else, since the rest needs to contact the
admin server.
- startManagedWebLogic.cmd TopsecurityNode1 http://localhost:7001
- startManagedWebLogic.cmd TopsecurityNode2 http://localhost:7001
- startManagedWebLogic.cmd TopsecurityProxy http://localhost:7001
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.
- In the left pane, expand Clusters.
- Click a cluster name that you want to monitor.

- In the right pane, click the Monitoring tab.

- 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:
- http://127.0.0.1:6001/toptime
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