Rails, Slashdotted: no problem

June 27, 2007 Brian Takita

By Steve Conover and Brian Takita

Peer-to-Patent, one of Pivotal Labs’ clients, got Slashdotted last week, and we had no trouble handling the load. The site was just as responsive as it always is, and we didn’t come close to having a scale problem.

Moral of the story: the technology for serving static web pages is old, boring, and extremely scalable. If you have the type of site that can be page-cached, do so aggressively, starting with the front page and any pages likely to be linked to. We got a huge payoff for the engineering time that we invested in our page-caching strategy.

Highlights:

  • We moved away from Rails page-caching and developed our own “holeless cache”, which uses a symlink trick (see below) to instantly and “holelessly” switch to a new version of a cached page. (The cache “hole” is the time between the expiration or purge of a cached page and the time when it’s regenerated. The danger is that in that time your Mongrels can be saturated with requests – something we proved to ourselves could easily happen.)
  • Here’s our symlink trick, using the front page as an example:
    1. Have index.html point to index.html.current
    2. If (index.html.current is >= 20 minutes old)
      1. Copy index.html.current to index.html.old
      2. Point index.html to index.html.old
      3. Rewrite index.html.current by asking Rails for the page (using the process method)
      4. Repoint index.html back at index.html.current
    3. Repeat step 2 every minute using a cron job.
  • For cache expiration that’s model-based, we make a call from the model observer class to our holeless cache routine, instead of using Rails cache sweepers. So, instead of just deleting the cached page we regenerate it in place.
  • It was important to write tests that proved that the HTML we generated for cached pages looked exactly the same in different “modes” (user logged in vs not, for example). This forced us to push modal decision logic out of Markaby templates and into JavaScript, meaning that view-oriented Rspec tests asserting modal differences became useless. We rewrote them as Selenium tests.
  • Performance/load testing: we tried several tools and approaches and found that a simple Ruby script that launches wget requests (that write to /dev/null) in many separate threads worked best for us.
  • We send down exactly one .js and one .css file. If you are sending down more than one of each of these to the browser, you have a performance problem. Fix it with asset packager.

Update: one clarification about the cron job: we deploy this “automatically” using capistrano.

About the Author

Biography

More Content by Brian Takita
Previous
Taming JavaScript in practice: AJAX with Protoype
Taming JavaScript in practice: AJAX with Protoype

In a previous post I discussed how to unit-test client-side AJAX JavaScript code using JsUnit. In that pos...

Next
Taming JavaScript in practice: AJAX
Taming JavaScript in practice: AJAX

Commonly the JavaScript side of AJAX ends up untested, tightly coupled to the server-side code, and difficu...