Y Be Slow?

Posted by & filed under Ruby on Rails.

When Yahoo! released it’s YSlow application last year as a plugin for the Firebug Firefox extension (because really, what web developers don’t have Firefox installed, even if it isn’t their primary browser?) nearly everyone installed the tool and started going down the list of rules Yahoo! laid down for improving “front-end performance” on websites. Several people wrote up suggestions for using the output to improve Rails apps, including a good summary for Nginx, but we’re using Apache.

“Front-end performance” means attacking speed as a problem between the browser and the server, and not as a problem which exists solely behind the server. We can optimize an application as much as we want, but if the browser makes thirty-five round-trips to the server fetching CSS, image files, and JavaScripts, application optimization isn’t helping much. In addition to grading apps on these fourteen points, YSlow gives a load time (in milliseconds!), and as your grade improves, you can also see the load time improving by perceptible intervals.

This afternoon I ran YSlow on the current development version of the La Cucina Italiana site. The initial grade was 52, an F. When I was done, it was 88, a B, and if I circumvent a dubious aspect of YSlow, it becomes a 98 A. I made only four changes: three Apache configuration tweaks and one Rails change. If you’re a Rails developer with Apache 2.2 in your stack, here are the low-hanging fruit for a better YSlow score. You can make these changes in your site configuration or within an .htaccess file.

ETags: The Yahoo! explanation of how ETags are important is a little confusing. The summary is this: you want to turn ETags off. They’re ineffective with multiple servers (i.e. an asset-server setup) and even if everything is on one host, there are other, just as useful means of avoiding downloads of cached files. So spare yourself that many bytes per connection and turn them off. It’s a one-line fix:

FileETag none

GZip components: The time saved by sending down compressed files is greater than the time spent compressing them, but only for text-based file types. (Images and PDFs are already compressed, so re-compression won’t help and might hurt.) If you’re using Coda Hale’s configuration for Apache and Mongrel (and many of us are) the code for compressing text components before download is already in your Apache configuration. However, Coda’s config misses one file type which Rails seems to use for Javascript, application/x-javascript, so YSlow keeps dinging us for uncompressed JavaScript files. With that added, the configuration for compression looks like this:

AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/javascript text/css application/x-javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch bMSIE !no-gzip !gzip-only-text/html

(Note that there should be only four lines there: one AddOutputFilterByType and then three BrowserMatch lines.)

Far-future cache expiration: Yahoo! is looking for really far future expiration dates for cache expiration. The reasoning here is to maximize the odds that your users are arriving at your site with a “primed” cache, i.e. one where most of your components are already loaded. By putting a way-out expiration on components, users keep those bits in their cache longer. The flip side is that filenames need to change in order to prompt the browser to load a changed file. Rails does this by automatically appending a timestamp to the filenames of many components. (Check your page source and see what is actually getting called when you load a CSS file.) Therefore, we can set our default expires header way out in the future.

This is a two-line addition to the Apache configuration:

ExpiresActive On
ExpiresDefault "access plus 10 years"

Reducing connection count: This is the tough one. Default Rails apps load a zillion (OK, seven) Javascript files and at least one but possibly many more CSS files, and that’s before we start with page images. Most browsers will only open two or three connections at a time to a given server, so all the files are waiting in line to get loaded. You can maximize the number of concurrent connections by using an asset server; this fools the browser into opening more connections by giving it more hosts to connect to. (This is like opening more Starbucks’ in the same town.) That doesn’t really save you, though, and it boosts the number of DNS lookups the browser needs to run. To really cut the number of JS and CSS files, you need to bundle assets. It’s possible to bundle images, but that’s not a problem for LCI, which has only four or five images on the home page. Bundling JS and CSS is where the action is.

There are multiple ways to do this, including a nifty program called AssetPackager and the caching code built in to Rails 2.0. We went with what we saw as the simplest route, which was bundle_fu, but we have an eye on AssetPackager for future consideration. bundle_fu is a Rails plug-in which takes all the CSS and JS files for a template and concatenates them into one CSS and one JS file, sometimes even minifying the JS. It’s a quick installation, and not only does it convince YSlow to give your site a good grade on the number of connections, it also gives good grades for “Put JS at the bottom” and “Minify JS” because, hey, there’s only one file, right? This one move improved our YSlow score more than any other step.

The score at this point: 88 points, a high B. We’re still suffering for not having minified our JS (a little, and we’ve decided not to bother, since it’s being gzipped anyway) and for not using a CDN.

Cheating: The CDN point is one of the most hotly-contested on the YSlow report card, because most sites as small as ours see very little return on the investment of putting our site on a Content Delivery Network such as Akamai. It’s possible, though, to get YSlow to turn a blind eye to your CDN-less-ness. Just add your own site’s domain to the list of CDN servers in YSlow’s preferences. Doing that jumped our score up to 98–pretty close to perfect.

Unfixable: One thing which may keep your site from ever having a good YSlow report is using a lot of outside components. Common Kitchen gets dinged because its page loads include calls to two different ad networks, not to mention multiple images from Amazon on some pages and the Google Analytics code. This makes for a lot of un-bundle-able scripts, multiple DNS requests, and a lot of components where we don’t control their ETags (or lack thereof), expiration header, or compression. Of course, we can’t control their server uptime, either, so it may be that the YSlow scores are the least of our problems!

9 Responses to “Y Be Slow?”

  1. Sreenath

    i need to Gzip the componenets css,js files which appearing for the web page .With the tool YSlow i identified that there are the compenenets which are not Gzip. we are using apache2.2 version .please provide the code to place in .httpaccess file .

    For my web page it showing Grade F for the Gzip Componenets. reply me

  2. pjmorse

    Sreenath, the four configuration lines above (under “GZip Components”, starting with AddOutputFilterByType DEFLATE) are the ones you want. Notice that for them to work in an .htaccess file, your host will need to have enabled directory-level configuration overrides; otherwise the .htaccess file will be ignored.

  3. pjmorse

    Sreenath, if you have control over the full Apache configuration (e.g. if this is a VPS) you can add that line to the virtual host configuration block. Otherwise, you should ask your hosting provider how to enable compression on .js and .css files.

  4. Domain Flipping

    I strongly recommend that you turn the No Follow off in your comment section.

    I’ll watch Google Webmaster Tools, and if the links don’t show up after a couple of weeks — I won’t go back to that blog again.

    Another suggestion: you should have a Top Commentator widget installed.

    Do Follow and Top Commentator will ensure that you have a successful blog with lots of readers!

  5. pjmorse

    Domain Flipping: What a confidence-inspiring name you have! And what relevant advice to the entry on which you commented!

    I appreciate your pointing out the nofollow issue; it seems to be too blunt an instrument for its purpose, and I have in fact turned it off. “Top Commenter” seems too much like a contest, however; I don’t care how often people comment, I care that they add useful ideas. (And, I should point out, the usefulness of their ideas is often in inverse proportion to their determination to push the URL of their business.)

    To be more blunt, the steps you are suggesting sound to me like they’re designed to cater to those who wish to build their page-rank by planting their own URLs in as many places as possible on the site, regardless of the relevance or utility of those URLs to the content we’re attempting to provide. I think your motives and ours do not overlap terribly much.

  6. eRage webdesign

    These sound like pretty good tips. I’m developing a “general” .htaccess for most websites we’re developing here.

    Here’s my take on the whole optimization story:

    # Deflate on
    AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml text/javascript text/css application/x-javascript application/xhtml+xml application/javascript
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4.0[678] no-gzip
    BrowserMatch bMSIE !no-gzip !gzip-only-text/html
    Header append Vary User-Agent env=!dont-vary

    # ETag off
    Header unset ETag
    FileETag None

    #Expires on
    ExpiresActive On
    ExpiresDefault A0
    ExpiresByType application/x-javascript “access plus 1 weeks”
    ExpiresByType text/css “access plus 1 weeks”
    ExpiresByType image/gif “access plus 1 weeks”
    ExpiresByType image/png “access plus 1 weeks”
    ExpiresByType image/x-icon “access plus 1 weeks”
    ExpiresByType image/ico “access plus 1 weeks”
    ExpiresByType image/jpeg “access plus 1 weeks”
    ExpiresByType application/x-shockwave-flash “access plus 1 weeks”
    ExpiresByType video/x-flv “access plus 1 weeks”

    That’s the .htaccess part. Also, I like putting Javascript files at the bottom of the page for quicker loading. Hope I helped you guys with this!

Leave a Reply

You must be logged in to post a comment.