{"id":78,"date":"2009-02-16T14:16:45","date_gmt":"2009-02-16T21:16:45","guid":{"rendered":"http:\/\/www.zulutown.com\/blog\/?p=78"},"modified":"2009-02-16T14:16:45","modified_gmt":"2009-02-16T21:16:45","slug":"java-ee-load-balancing-with-tomcat-and-apache","status":"publish","type":"post","link":"https:\/\/www.zulutown.com\/blog\/2009\/02\/16\/java-ee-load-balancing-with-tomcat-and-apache\/","title":{"rendered":"Java EE Load Balancing with Tomcat and Apache"},"content":{"rendered":"<p>This tutorial explains how to configure an <em>Apache HTTPD<\/em> server to map a specific path on a series of load-balanced <em>Apache Tomcat<\/em>.<br \/>\nThe first step is to define the <em>Virtual Host<\/em> in the Apache configuration files.<br \/>\nIn this case the root directory (on file system) of the site is located in <code>\/path\/to\/your\/site\/<\/code>, the name of the site is <code>www.yoursite.com<\/code> and the path where the Tomcat servers may be reached is <code>\/javaee<\/code>.<\/p>\n<p>In few words, an URL like <code>http:\/\/www.yoursite.com\/home.html<\/code> is mapped on the file <code>\/path\/to\/your\/site\/home.html<\/code>.<\/p>\n<p>An URL like <code>http:\/\/www.yoursite.com\/javaee\/hello.jsp<\/code> is mapped to the <code>hello.jsp<\/code> file contained in <code>javaee.war<\/code> application deployed on all the Tomcat servers defined in the <em>load balanced cluster<\/em>.<\/p>\n<p>The configuration of the Apache virtual host:<\/p>\n<pre>&lt;VirtualHost *&gt;\r\n\tServerAdmin webmaster@localhost\r\n\tServerName www.yoursite.com\r\n\tDocumentRoot \/path\/to\/your\/site\/\r\n\t&lt;Directory \/path\/to\/your\/site\/&gt;\r\n\t\tOptions MultiViews\r\n\t\tAllowOverride All\r\n\t\tOrder allow,deny\r\n\t\tallow from all\r\n\t&lt;\/Directory&gt;\r\n\r\n\tErrorLog \/var\/log\/yoursite-error.log\r\n\r\n\tLogLevel warn\r\n\r\n\tCustomLog \/var\/log\/yoursite-access.log combined\r\n\r\n    &lt;Proxy balancer:\/\/tomcatservers&gt;\r\n\tBalancerMember ajp:\/\/tomcatserver.yoursite.com:8009 route=tomcatA retry=60\r\n        BalancerMember ajp:\/\/tomcatserver.yoursite.com:8010 route=tomcatB retry=60\r\n\tBalancerMember ajp:\/\/tomcatserver.yoursite.com:8011 route=tomcatC retry=60\r\n    &lt;\/Proxy&gt;\r\n\r\n    &lt;Location \/javaee&gt;\r\n\tAllow From All\r\n        ProxyPass balancer:\/\/tomcatservers\/javaee stickysession=JSESSIONID nofailover=off\r\n    &lt;\/Location&gt;\r\n\r\n&lt;\/VirtualHost&gt;<\/pre>\n<p>The most important settings are <code>Proxy<\/code> and <code>Location<\/code>.<br \/>\nIn <code>Proxy<\/code> it&#8217;s defined a <em>load balancer<\/em> made with 3 tomcat servers and an URL is assigned to the balancer, in this case <code>balancer:\/\/tomcatservers<\/code>.<\/p>\n<p>The balancer has three members, everyone with its own URL based on the <code>ajp<\/code> protocol. In this case Apache will connect to the Tomcat servers on their <em>AJP connectors<\/em> (an alternative would be to use their <em>HTTP connectors<\/em>).<\/p>\n<p>The Tomcat servers run on the <code>tomcatserver.yoursite.com<\/code> hostname and each of them opens its own AJP connector on a different port: the first on <code>8009<\/code> (the default one), the second on <code>8010<\/code>, the third on <code>8011<\/code> (obviously if they run on the same hostname\/IP they must bind to different ports).<\/p>\n<p>Each Tomcat is identified by a route name: <code>tomcatA<\/code>, <code>tomcatB<\/code> and <code>tomcatC<\/code>. The importance of it will be explained later.<\/p>\n<p>In the <code>Location<\/code> section, a specific path <code>\/javaee<\/code> of the virtual host is mapped on the previously defined balancer <code>balancer:\/\/tomcatservers\/javaee<\/code>. So when someone asks for <code>http:\/\/www.yoursite.com\/javaee\/hello.jsp<\/code> the virtual host will request that JSP to a randomly chosen Tomcat in the balancer members.<\/p>\n<p>What&#8217;s the <code>stickysession<\/code> attribute? It&#8217;s a very useful configuration parameter used in conjunction with the <code>route<\/code> attributes, defined before.<\/p>\n<p>As probably every Java EE (or Web) developer should know, while browsing on a server, it keeps trace of some data about the browsing session in a server-side <em>HttpSession<\/em> object. For example an ecommerce web application needs to store somewhere the information about the shopping cart of non registered users.<\/p>\n<p>How the server can associate the remote session data with the specific navigation session? This is done through a cookie (or via a GET parameter in the URL) that gives to the server the <em>session ID<\/em> value.<\/p>\n<p>In Java EE applications, the cookie name to identify the sessions is <code>JSESSIONID<\/code>.<\/p>\n<p>This is closely related to the management of the load balancing between the Tomcat servers.<\/p>\n<p>If Apache picked randomly one of the Tomcat to handle a single request and if the next request from the same user\/browser was forwarded by the balancer <em>to another Tomcat<\/em> in that battery, things wouldn&#8217;t work correctly.<\/p>\n<p>Each Tomcat doesn&#8217;t know anything of the existence of other Tomcat in that balancer configuration and especially a single Tomcat server cannot access the information of <em>http sessions<\/em> handled by another Tomcat.<\/p>\n<p>In few words, when a Tomcat is chosen to handle the first request from a user\/browser, it&#8217;s absolutely required that, to keep valid session data, the same Tomcat must be used to handle the following requests coming from that browser\/user.<\/p>\n<p>If not, on each request, the session data would be lost and simple tasks, such as building a shopping cart would result impossible.<\/p>\n<p>So, it&#8217;s required to tell to Apache what is the session cookie name: <code>JSESSIONID<\/code> and which is the identifier of the routes to each single tomcat Server: <code>tomcatA<\/code>, <code>tomcatB<\/code>, <code>tomcatC<\/code>.<\/p>\n<p>In this way, Apache will append to the end of the cookie value the information about the route to the specific Tomcat.<\/p>\n<div id=\"attachment_83\" style=\"width: 490px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-83\" class=\"size-large wp-image-83\" title=\"Java EE Tomcat Load Balancing\" src=\"http:\/\/www.zulutown.com\/blog\/wp-content\/uploads\/2009\/02\/javaee-tomcat-load-balancing-480x320.png\" alt=\"Java EE Tomcat Load Balancing\" width=\"480\" height=\"320\" srcset=\"https:\/\/www.zulutown.com\/blog\/wp-content\/uploads\/2009\/02\/javaee-tomcat-load-balancing-480x320.png 480w, https:\/\/www.zulutown.com\/blog\/wp-content\/uploads\/2009\/02\/javaee-tomcat-load-balancing-300x200.png 300w, https:\/\/www.zulutown.com\/blog\/wp-content\/uploads\/2009\/02\/javaee-tomcat-load-balancing.png 718w\" sizes=\"auto, (max-width: 480px) 100vw, 480px\" \/><p id=\"caption-attachment-83\" class=\"wp-caption-text\">Java EE Tomcat Load Balancing<\/p><\/div>\n<p>Finally, the last thing to set-up Apache, is obviously to add to it the  modules required by the previous configuration:<\/p>\n<ul>\n<li>proxy<\/li>\n<li>proxy_balancer<\/li>\n<li>proxy_ajp<\/li>\n<\/ul>\n<p>About Tomcat configuration, there are just few changes to apply to the default configuration, in the <code>Engine<\/code> section it&#8217;s required to add the <code>jvmRoute<\/code> attribute.<\/p>\n<pre>&lt;Engine name=\"Catalina\" defaultHost=\"localhost\" jvmRoute=\"tomcatA\"&gt;<\/pre>\n<p>This is related to the <code>route<\/code> parameter defined in the Apache load balancer. So, <code>tomcatA<\/code> should be set in the configuration of the first Tomcat server, <code>tomcatB<\/code> in the second and <code>tomcatC<\/code> in the third one.<\/p>\n<p>Then, the port where <em>AJP connector<\/em> listens, has to be set accordingly to the apache configuration, so <code>8009<\/code>, <code>8010<\/code>, <code>8011<\/code> respectively on the first, second and third Tomcat.<\/p>\n<p>The following is the the configuration of the <em>AJP connector<\/em>:<\/p>\n<pre>&lt;Connector port=\"8009\" protocol=\"AJP\/1.3\" redirectPort=\"8443\" \/&gt;<\/pre>\n<p>It&#8217;s not directly related to the setup of the load-balancer, but since they run on the same host, each Tomcat should have its own set of ports.<\/p>\n<p>To prevent any conflict you should change the following settings on the second and third servers: <code>Server port=\"8005\"<\/code> and <code>Connector port=\"8080\"<\/code>.<\/p>\n<p>I hope this tutorial has given a complete overview about every step required to setup <em>Apache<\/em> and <em>Tomcat<\/em> to create a simple load-balanced cluster.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial explains how to configure an Apache HTTPD server to map a specific path on a series of load-balanced Apache Tomcat. The first step is to define the Virtual Host in the Apache configuration files. In this case the &hellip; <a href=\"https:\/\/www.zulutown.com\/blog\/2009\/02\/16\/java-ee-load-balancing-with-tomcat-and-apache\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[40,11,4],"tags":[41,171,47,52,51,168,45,44,43,42,48,50,49,46,165],"class_list":["post-78","post","type-post","status-publish","format-standard","hentry","category-apache","category-java-ee","category-tomcat","tag-ajp","tag-apache","tag-balancermember","tag-cluster","tag-connector","tag-java-ee","tag-jsessionid","tag-jvmroute","tag-load-balancer","tag-load-balancing","tag-mod_proxy","tag-mod_proxy_ajp","tag-mod_proxy_balancer","tag-stickysession","tag-tomcat"],"_links":{"self":[{"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/posts\/78","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/comments?post=78"}],"version-history":[{"count":5,"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/posts\/78\/revisions"}],"predecessor-version":[{"id":84,"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/posts\/78\/revisions\/84"}],"wp:attachment":[{"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/media?parent=78"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/categories?post=78"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.zulutown.com\/blog\/wp-json\/wp\/v2\/tags?post=78"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}