Sunday, February 24, 2008

High Performance Web Sites and Tomcat

I recently attended a Boulder Java User Group meeting, at which Scott Davis pointed us to YSlow, a website performance analysis tool. It is an add-on to the Firebug plug-in. When analyzing a web site, YSlow takes into account 10-15 criteria, and gives a grade.

As an aside, this is exactly why I attend the BJUG. I often pick up information that is instantly useful in my day-to-day software development. Another gem I recently discovered at BJUG is YUI, which I now use extensively both at work and for my own personal projects. YUI is to front-end development as Spring is to middle-tier development. In particular, YUI makes the life of the developer much easier.

At any rate, I analyzed my own web site,, with YSlow, and was given an 'F' for performance. Here is the full analysis:

Performance Grade: F (58)

B 1. Make fewer HTTP requests
F 2. Use a CDN
F 3. Add an Expires header
F 4. Gzip components
A 5. Put CSS at the top
A 6. Put JS at the bottom
A 7. Avoid CSS expressions
n/a 8. Make JS and CSS external
D 9. Reduce DNS lookups
A 10. Minify JS
A 11. Avoid redirects
A 12. Remove duplicate scripts
F 13. Configure ETags

To improve this grade, I have been focusing on 3,4, and 13, all of which require manipulation of the Apache HTTP Server's httpd.conf file.

The problem that I am encountering is I actually use Tomcat to serve all my web content including static resources (e.g. javascript, CSS files). I only use Apache HTTP Server as a proxy server to forward web traffic to Tomcat. My attempts at manipulating the httpd.conf file yield nothing. For example, when I insert these lines into the httpd.conf file:

<ifmodule mod_expires.c>
<FilesMatch "\.(png|css|js)$">
ExpiresActive on
ExpiresDefault "access plus 10 year"

it does not add any expires header to my CSS or javascript files. You can see this for yourself if you have Firebug and YSlow installed.

Perhaps there is some other explanation, but I presume this is happening because I am only using Apache HTTP Server as a proxy. All header information is actually supplied by Tomcat.

A possible solution is to have the Apache HTTP Server serve all my static resources, and have Tomcat only serve content relevant to the web application. The problem with this approach is that it makes deployment a real pain in the neck. I have to split my deployment between the HTTP Server and Tomcat. Moreover, I would also have to figure out how to selectively forward requests to Tomcat depending on what is requested (i.e. static versus dynamic content). I do not know how difficult this is to implement since I have not tried, but it just feels convoluted and kludgy. It would probably require a fair amount of trial and error mucking with the httpd.conf file.

Another potential solution is to programmatically add these headers within my web application, but this approach is somewhat absurd.

So my question is, is there a simpler solution to improving weathermole's performance?