Load testing: Why use tools when you can use Ruby?

15 October 2012, by

I recently found myself dealing with a problem that had been identified in load testing on one of our customer’s sites. Specifically, when the site was being hit with requests for mobile pages while also handling a background noise on the desktop versions, one of those desktop pages would, every so often, throw a 500 error. The mobile pages in isolation worked fine, and the desktop pages in isolation worked fine.

This kind of bug is one of those ones that I feel is allowed to happen during dev, so I didn’t feel too bad about it. In order to actually diagnose and fix the issue, however, I was clearly going to need to generate some load of my own so I could work out the problem rather than merely the symptoms.

The trouble with JMeter

JMeter is a fairly widely-used load testing tool, one which I’ve seen used live in conference presentations and which is, I believe, the de-facto standard tool for running load tests if you don’t want to pay for anything. While it does have that ominous J at the start which many of you .NET types might be put off by, it is completely separate to your application and so integrates with whatever you’re doing.

The theory is that you can set up a load of URLs you want to hit, the number of threads you want to have aiming at it, the (approximate) rate at which you want to hit those URLs, etc. and get useful read-outs of response times, any errors etc.

In practice, it crashed half the time and I wasn’t actually interested in the read-outs. For my bug, I just needed to maintain sufficient load and then go to the problematic page myself to actually see what was going on. Nor did I care for dealing with its frequent crashes and sketchy documentation.

Enter Ruby

At the basic level, all I needed to do was to hit 16 different URLs at different rates (you don’t want to be hitting the less traffic-heavy pages as much as you’re hitting the home page, after all), which I could almost have done manually if I were an octopod. Getting JMeter to work for my purposes looked like it would take about as long as growing those extra limbs, so I decided to look elsewhere. Looking elsewhere turned up a bunch of tools that looked like they were going to offer much the same as JMeter, but would also involve the exchange of money, so I decided to do it myself.

It’s been said many times before, but merits repeating: in situations like this Ruby (or any scripting language) is almost always your friend. I wrote a little script that would just hit my chosen URLs at an appropriate rate for an appropriate length of time so that could I visit my problem page while it was going on and see what happened. It looked like this:

baseUrl = "_customer url removed_"

def loadUrl url, rate
  subbed = url.gsub(/W/, '_')
  i = 0
  while i < 40 / rate
    command = "wget -O #{subbed}#{i}.html http://#{baseUrl}/#{url}"
    Thread.new do
    sleep rate
    i += 1

def runLoad conf
  conf.each do |url, rate|
    Thread.new do
      loadUrl url, rate

config = {
  'music' => 1,
  'music/reviews' => 2

runLoad config

…but with more config for more URLs. It kicks off lots of threads (I wasn’t that bothered about whether ruby could actually handle enough threads, as long as a decent load was maintained) so that we don’t end up waiting synchronously, and hits those URLs in proportion to the numbers. As configured above, it will hit the first URL every second, and the next every two seconds, for a total of forty seconds.

Is it pretty? No.
Is it likely to work exactly as specified? Probably not, because I doubt that the threading would scale nicely.
Did it work well enough for me to diagnose and fix my problem? Yes.

It also wrote the results of each request to a file so I could check that the same thing got returned each time by skimming the file sizes. It turns out that for some pages that wasn’t the case, but that’s a different issue.


I’m sure that tools like JMeter are very useful when you need to get detailed information about how your system performs under load. Sometimes, however, you just need to hammer a site for a bit to see what happens, and that really doesn’t take a lot of code at all…

Tags: , , , ,

Categories: Technical


Leave a Reply

* Mandatory fields

× nine = 27

Submit Comment