Transparent Application Deployment with Tomcat and JK
If you've ever wanted to get some kind of software load balancing configuration working with Tomcat using the JK Connector, then this article may be for you. More importantly if you've ever wondered how to make production builds transparent to users in J2E development with Tomcat and you don't have a hardware load-balancing budget available, this may also be for you. I work with 1 production server in my work place that delivers the corporate intranet via 1 web application. Being an intranet, there are often several to many patches per week of small to large magnitude. Unfortuantely we cannot patch single classes like we can JSPs due to the JVM (big shame), so we need to come up with another way to deploy web applications that do not pull down the application from users for too long. Now, I don't really like to pull the intranet down at all to deploy changes as we have international customers. Also because it's inconvenient to me as a developer, it may be there's an urgent fix that I want done silently, or general politics about availability. The issue is more pressing for internet sites too where as close to 100% availability is desirable. With load balancing, the general strategy is to provide a single point of access for inbound requests to the web application and then based on some rules, e.g round-robin or weights, send the request to a particular server to handle the request. Load balancing is usually used for performance and high-availability strategies. You will often find load balancing is done by a piece of hardware that sits in front of 2 logically separate servers. If you can afford it, do it. If you're limited in budget or hardware, then what I am about to talk about will provide a strategy for permanent availability with 1 Tomcat server. It does have caveats with respect to sessions however (unless you setup session clustering).Install another Tomcat
I already had 1 Tomcat installed and running the web application. I simply copied the apache-tomcat folder to apache-tomcat-2, complete with web application. I don't use the Windows installer, I use the ZIP distribution as it offers more flexibility for my taste. I will refer to each Tomcat as TC1 and TC2 TC2's apache-tomcat/conf/server.xml file needed some changes for ports so as to prevent bind exceptions. I changed the main Server element port to 8006 (TC1 is 8005), the HTTP Connector to 8081 (TC1 is 8080) and the AJP port to 8109 (TC1 has 8009). Note to use JK you need to use the AJP Connector. Both server.xmls for TC1 and TC2 also need a modification to the Engine element. A new attribute is required (thanks to the Tomcat Users list for this information). You need to add the jvmRoute attribute with a name that matches the worker name for the Tomcat in question. The worker name is that which you call the worker in the workers.properties configuration (discussed later so just ensure you come back to this attribute). That is all that is needed in terms of configuration difference between TC1 and TC2. Obviously, I modified my build process so that when I build new code, both Tomcats get the new code.JK
This is the part that really matters and for which I had trouble finding examples on the web. I am assuming you have configured and have working a normal JK setup? You do right? So, here is my workers.properties fileworker.tomcat1.port=8009 worker.tomcat1.host=localhost worker.tomcat1.type=ajp13 worker.tomcat1.lbfactor=1 worker.tomcat2.port=8109 worker.tomcat2.host=localhost worker.tomcat2.type=ajp13 worker.tomcat2.lbfactor=1 worker.loadbalancer.type=lb worker.loadbalancer.balance_workers=tomcat1,tomcat2 worker.loadbalancer.sticky_session=1Both Tomcats are defined as tomcat1 and tomcat2. Note that these are the worker names I referred to earlier when talking about the jvmRoute attribute of Engine. Make sure that TC1's Engine's jvmRoute="tomcat1" and TC2's Engine's jvmRoute="tomcat2". Also note that you must not use these workers in the workers.list setting. Instead, you create a worker called loadbalancer (a special type of worker indicated to JK by setting it's type to lb) and add the tomcat1 and tomcat2 workers to this using the balance_workers property, and then the workers.list should be just the loadbalancer worker. Also for the loadbalancer, I have explicitly set the sticky_session property to 1 (which is default anyway). This means that JK will examine a request for a JSESSIONID and try and match it to a known active session on a Tomcat worker. If it's found and the Tomcat is available, the request will be forwarded to that Tomcat. Don't forget the URI mappings! Don't forget to modify your URI mappings to map to the loadbalancer worker now instead of a named worker.
/*.do=loadbalancer /jsp-examples/=loadbalancer /servlet-examples/=loadbalancerRestart the web server (in my case IIS) so the JK settings take effect. Also bring up both Tomcats and verify they are happy to co-exist.














