Load balance web application

user32262 picture user32262 · May 13, 2009 · Viewed 11.5k times · Source

There are load balanced tomcat web servers. Every request could be served by different tomcat server.

How could we take care of this while writing code for the j2ee (struts) based web application?

Answer

matt b picture matt b · May 13, 2009

First of all, you'll want to set up your load balancer for session affinity/sticky sessions, so that it continues forwarding all requests to the same Tomcat (as long as it is up) based on JSESSIONID.

The Tomcat clustering doc states two important requirements for your application to successfully have it's sessions replicated:

  • All your session attributes must implement java.io.Serializable
  • Make sure your web.xml has the <distributable/> element or set at your <Context distributable="true" />

If you start putting Objects into Session which don't implement Serializable (or which have properties/fields that don't implement Serializable), then you're going to have problems.

(Actually these points all apply regardless of which servlet container you are using, I believe.)

Update: To address some of the questions in the comments about why use sticky sessions when you are balancing the load between multiple servers, I think it's easiest to explain this with an example.

First of all, this only really matters if your application keeps some sort of data in-session, which may not be every single application (although it's probably most). If you don't keep data in-session then you probably won't care about any of this and you can just stop reading here.

Having an environment where you keep data in session but you do not have sticky session would open up a world of headaches.

Let's say first.jsp updates some value in a particular session attribute, and second.jsp happens to read this same session attribute. You can set up Tomcat to replicate session data to all servers in the cluster, but this replication does not occur instantly. What if the initial request for first.jsp is handled by server1 and one nanosecond after it completes, the same visitor makes a request to second.jsp, which in your non-sticky environment gets handled by server2. Since replication is not instantaneous, do you have any way of knowing if you are reading the most up-to-date session data? Do you have to add some sort of logic to synchronize your reads across the cluster? This would become giant pain.

Setting up session affinity/sticky sessions removes this headache; by having all requests from the same client server by the same node, you don't have to worry about "is this node up to date by the time it handles the request?" When the node fails, the client can still failover to another node in the cluster, which has a copy of it's session data, but with sticky sessions this becomes the rare case and not the norm.

There is another reason to want sticky sessions: load between the nodes in the cluster. If a request in a session could be handled by any node, then that would imply that you have all-to-all replication set up in the cluster (meaning the session data of node1 is replcated to node2, node3, ..., node N, the session data of node2 is replicated to node1, node3, ... none N, etc). All-to-all session replication can become bandwidth and resource intensive when the cluster gets larger, because each addition to the cluster means yet another node that needs to communicate with every other single node in the cluster.

An alternative to this is have a node's data replicated to only a few "buddies" in the cluster, so that in case the node fails it's data is available elsewhere but without every single node having to have a copy. In this scenario, you would configure the cluster so that node1 has it's data replicated to nodes 2 and 3, node 2 has it's data replicated to nodes 3 and 4, etc., forming a chain. In this scenario, adding additional nodes to the cluster does not cause the amount of communication between nodes to increase rapidly as it does in an all-to-all scheme.