Search This Blog

Loading...

Sunday, March 6, 2011

Tomcat load balancing

I will demonstrate tomcat load balancing by connecting apache web server and tomcat application servers through ajp connector.

In this example I use mod_proxy and mod_proxy_ajp which is built into Apache web server from versions 2.2 and up. AJP stands for Apache Jserv Protocol wich is binary packet-oriented protocol and apache web server communicates with tomcat over TCP connections, maintains persistent connections and reuses a connection for multiple request/response cycles. 

By having apache web server in front of multiple tomcat application servers you can achive to handle more concurent requests and also have some sort of failover in case one of the nodes breaks down.
Good thing is also that you can serve your static content like images, javascript and css files from apache web server(apache web server is somewhat faster in serving static content than tomcat), and let the tomcat application server to handle the real applcation processing.

For example purposes I'll install two tomcat application servers and apache web server on the same physical machine but in the real world that would probably be separate machines.

1. First, I install two separate instances of tomcat application servers(download and unzip). You will need to change the ports in server.xml config file to avoid port conflicts.
Tomcat A
<Server port="8005" shutdown="SHUTDOWN"> 
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcatA">
Tomcat B
<Server port="8006" shutdown="SHUTDOWN"> 
<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcatB">
Last line has attribute jvmRoute and is concerned to session stickyness explained further bellow.
For test purposes deploy some dummy application under /balance context.
Try to start both instances to see if everything is ok.

2. Install apache web server. I am using Ubuntu:
sudo apt-get install apache2

3. Edit virtual host configuration file.
On Ubuntu, I edit /etc/apache2/sites-enabled/000-default.

<Proxy balancer://tomcatservers>
    BalancerMember ajp://localhost:8009 route=tomcatA loadfactor=1
        BalancerMember ajp://localhost:8010 route=tomcatB loadfactor=2
    </Proxy>

    <Location /balancetest>
    Allow From All
        ProxyPass balancer://tomcatservers/balance stickysession=JSESSIONID nofailover=off
    </Location>
We defined load balancer for two nodes (tomcatA and tomcatB) and proxy pass for load balancer. In proxy pass we defined that all request going to /balancetest are proxied to tomcat application server to /balance context. Entering url http://localhost/balancetest will display jsp page or whatever either from tomcatA or tomcatB depending on load balancer.

The load balancer supports session stickyness wich means that all request for some session identifier are proxied to same tomcat web application instance in cluster that first served the client. To track this information tomcat adds jvmRoute information that uniquely identifies tomcat application server in the cluster.

So, jsessionid cookie would look something like this:
jsessionid=4C87288CB0CDB71D0DCA412E178A1480.tomcatB

Apache web server will compare route  value defined in balancer with cookie value to proxy request to tomcat instance that maintains corresponding session.
It is important that jvmRoute attribute in server.xml config file and route attribute in virtual host config file are identical for some tomcat instance.

Load factor attribute allows to distribute load between nodes. If load factors are equal, load is equally distributed. In our case tomcatB will recieve two times more requests than tomcatA.

4. And for this to work following modules must be enabled on apache server.
  • proxy
  • proxy_balancer
  • proxy_ajp
On Ubuntu, you can do this from console by typing a2enmod command.
a2enmod proxy
a2enmod proxy_balancer
a2enmod proxy_ajp


Restart apache and tomcat servers and you'll have load balancing set up with minimal configuration.

2 comments:

  1. This is such an elegant solutionm My firm is delighted to find, implement and cut costs
    where the alternative was a specific router
    with additional IT involvement.

    - Juraj

    ReplyDelete
  2. am getting this error when try to do in Ubuntu

    Wed Sep 26 12:33:58 2012] [error] ajp_check_msg_header() got bad signature 4854
    [Wed Sep 26 12:33:58 2012] [error] ajp_ilink_receive() received bad header
    [Wed Sep 26 12:33:58 2012] [error] ajp_read_header: ajp_ilink_receive failed
    [Wed Sep 26 12:33:58 2012] [error] (120007)APR does not understand this error code: proxy: read response failed from (null) (192.168.1.108)
    [Wed Sep 26 12:33:58 2012] [error] ajp_check_msg_header() got bad signature 4854
    [Wed Sep 26 12:33:58 2012] [error] ajp_ilink_receive() received bad header
    [Wed Sep 26 12:33:58 2012] [error] ajp_read_header: ajp_ilink_receive failed
    [Wed Sep 26 12:33:58 2012] [error] (120007)APR does not understand this error code: proxy: read response failed from (null) (192.168.1.121)

    ReplyDelete