Arie’s Blog

Ruby web server performance

February19

I’m currently helping a colleague to build a rather large community website using Ruby on Rails. As most Rails developers are well aware, Ruby isn’t exactly the quickest language you can use to build web applications. To get a rough idea of how much users our current code would handle, I decided to run some performance tests.

First, here’s a picture of the page that was used.

Leef je Doel index page

The page has a tagcloud, site statistics and a conditional menu in the upper right corner.

For the benchmark I’m using the following tools

ApacheBench 2.0.40. To fire off a large amount of requests into the webserver.

Mongrel 1.1.3. One of the Ruby web servers

Thin 0.6.4. An alternative to Mongrel.

nginx 0.5.26. A lightweight HTTP server, which will act as a proxy/balancer in front of the Ruby application servers

For the benchmarks I settled on the following scenario’s.

Single instance of Mongrel in development mode

Single instance of Mongrel in production mode

Cluster of 4 Mongrel instances behind nginx

Cluster of 4 Thin instances behind nginx

In a real production environment, you’d never see the single Mongrel instance, and certainly not in development mode. The graph will show you why.

The red bar is for 50 concurrent requests, with a total of 10000. The red blue is for 10 concurrent requests, with a total of 10000.

Benchmark graph

The raw numbers:

  10 concurrent 50 concurrent
Mongrel (development) 4.88 req/s 4.59 req/s
Mongrel (production) 77.15 req/s 67.18 req/s
Mongrel cluster + nginx 130.97 req/s 122.04 req/s
Thin + nginx 156.21 req/s 160.89 req/s

I’m pleased with the results, we still have a lot of stuff we could cache and database queries that could be optimized, so there’s room for improvement. The server that will eventually host the application runs an Apache proxy going to mongrel_cluster. I’m probably going to run some benchmarks later, to see how Apache proxy holds up against nginx.

Nvidia GPU temperature screenlet

December6

All screenletsToday I rediscovered screenlets for Ubuntu. If you don’t know what screenlets are, click on the thumbnail on the right.

On my old laptop I tried using them before, but the poor thing couldn’t handle it.

Now with my new laptop I decided to give it another go.

Using compiz-fusion you can put these screenlets on a special ‘widget layer’, which you can summon by pressing a keyboard key. Temperature screenletsWhenever you need some information or need to make a small note, you press that keyboard key and the widget layer is displayed. Pressing the same key again and the widgets disappear.

There’s a nice screenlet that displays some sensor information, CPU and HDD temperatures. However, my laptop has another sensor on the graphics card that shows the GPU temperature. I just had to have this added to the screenlet.

I made a modified version of the Temperature2 script to generate a screenlet for nvidia GPU temperature. You’ll need the proprietary nvidia drivers installed and access to the ‘nvidia-settings’ utility. Download the file and place it in the ~/.screenlets/Temperature2/ directory, overwriting the old file.

Update: My modifications are now included into version 0.4 of Temperature2. You can get it at screenlets.org

Book on BDD in Ruby with RSpec

November15

RSpec book

I was browsing through this excellent presentation given by Dave Astels and David Chelimsky at RubyConf2007. Turns out that David Chelimsky and Aslak Hellesøy are working on a book about Behaviour Driven Development using RSpec.

The presentation is an excellent introduction for anyone thinking about moving to RSpec. It tells you a bit about the (rather short) history of the framework and the differences between BDD and TDD.

It also shows off the awesome plain-text stories I posted about earlier.

Story-based acceptance testing

November15

In my previous post I talked a bit about Behaviour Driven Development and RSpec’s beautiful syntax for writing specifications.

This week I stumbled upon acceptance testing in RSpec and a very pretty way of writing those tests.

A simple acceptance test would look like this:

Story: A user sends an invitation

The invitation page should allow users to invite friends

Scenario: Sending an invitation
Given a new unused email
When the user goes to /invite/create
And the user types 'Test' into the invite_name field
And the user types 'User' into the invite_surname field
And the user types 'someemail@email.com' into the invite_email field
And the user clicks the commit button
Then the page should contain the text 'Test User was invited'

Scenario: Sending an invitation to an already used email address
Given an already used email address someemail@email.com
When the user goes to /invite/create
And the user types 'Test' into the invite_name field
And the user types 'User' into the invite_surname field
And the user types 'someemail@email.com' into the invite_email field
And the user clicks the commit button
Then the page should contain the text 'Email already exists'

Now these tests don’t do anything by themselves, you need to run them against the application.
This is where Selenium comes in. Using RSpec’s story runner, you can feed these plain-text stories to Selenium.

Selenium will open your web application in a browser and go to URL’s, enter data, click buttons/checkboxes/radiobuttons. It’s kinda spooky to see your browser navigate to pages by itself ;)

Here’s another test that checks the login function

Story: A user logs in

Scenario: Logging in fails
Given a user with username 'Arie' and password 'test'
When the user goes to /login
And the user types 'Arie' into the login field
And the user types 'not-test' into the password field
And the user clicks the commit button
Then the page should contain the text 'Unable to login'

Scenario: Logging in successfully
Given a user with username 'Arie' and password 'test'
When the user goes to /login
And the user types 'Arie' into the login field
And the user types 'test' into the password field
And the user clicks the commit button
Then the page should contain the text 'Logged in'

For now I’m not planning on covering my entire application with tests like this. I’m just going to make a few tests that I can show to my school when I finish my internship.

Behaviour Driven Development

November8

I’m currently doing an internship as a final part of my study. Luckily I’ve been able to find a company where I can use Rails to create a new application.

One of the choices I made for the development is the use of BehaviourDrivenDevelopment (BDD), which is a variation on TestDrivenDevelopment (TDD).

Rspec is a BDD-framework for Rails. It features a beautiful way of expressing the expected behaviour of your application.

Here’s an example of the expected behaviour of a user controller

  it "should flash a notice after succesful signup" do
    User.should_receive(:new).with({"name" => 'Arie'}).and_return(@user)
    @user.should_receive(:save!)
    post 'signup', {:user => {:name => 'Arie'}}
    flash[:notice].should eql(_('Thanks for signing up, you will have to activate your account before you can log in'))
  end

And an example of expected behaviour of a user model

  specify "should be invalid with invalid zip code" do
    @user.attributes = valid_user_attributes.except(:zip)
    @user.zip = 'tralalalalala'
    @user.should_not be_valid
    @user.errors.on(:zip).should eql(_('is invalid'))
    @user.zip = '1234AB'
    @user.should be_valid
  end

The main idea of TDD and BDD is that you write these tests or specifications before writing the actual code. The basic workflow while doing BDD/TDD is:

1. Write tests/specifications

2. Run tests/specifications

3. See them fail because there’s no code yet

4. Code until tests no longer fail

It takes some discipline to strictly follow this pattern, because a future piece of code might seem so trivial, that you want to code it immediately.

rcov resultsWriting the specifications like this takes some time, but you’ll easily make up for it while you’re coding your application. You can use Rcov to check if your specifications cover all your code. When your specifications cover all your code with sensible tests, you can easily refactor your code, because the specifications will make sure your new code works properly.

Also, you can generate human-readable specifications from these rspec files, here’s a snippet of how that looks:

A user
- should be invalid without a username
- should have unique login name
- should be invalid without an email
- should be invalid if email is not between 3 and 100 characters in length
- should have unique email address

The UserController
- should redirect to profile after successfull activation
- should flash a notice when a valid activation code was used
- should flash an error when an invalid activation code was used

In combination with AutoTest, BDD is already saving me a lot of time during development.

Whenever I’ve changed some of my sourcecode or specifications, the specifications get tested automatically. If something breaks, there’s a small error popup, so you know you should check the AutoTest window for the test where it failed.

autotest error

Spot the typo

‘The User Controller should flash an error when an invalid activation code was used‘ FAILED
expected “Unable to activate the account.”, got “Unable to activate the accnt.” (using .eql?)

./spec/controllers/user_controller_spec.rb:29:
script/spec:4:

If all tests pass you get a cheerful message.

AutoTest success

Custom Ubuntu live CD

October2

Ubuntu logoIn a couple of days/weeks/months two friends and I will be giving a workshop at our school about Ruby On Rails. For this workshop we were looking for a bootable CD that provides a fully functioning Ruby on Rails dev environment.

We looked at RailsLiveCD.org but it wasn’t exactly the way we wanted. And whenever something isn’t exactly as you want in the world of OSS, you can fix it.

It took a great tutorial, some trial/error and a couple of failed CD’s, but finally I managed to get it just the way I wanted.

Ruby on Rails logoThe failed CD’s were due to the fact that ‘qemu’, an emulation program that you can use to test bootable .iso files, ran very slowly on my laptop.

The live CD is based on Ubuntu Feisty. It includes MySQL, vim-ruby, Aptana, ruby, rails and the sample project we’ll be using at the workshop.

No other live cd would have our own project on the disk :)

I’ll post the ISO once we’ve given the workshop.

Update

You can now download the Ubuntu on Rails iso.

Graphing HDD’s on Areca card in Cacti

September13

arecalogos.jpgI’ve previously posted about my migration from MRTG to Cacti and posted a graph showing the HDD temperatures of the disks connected to my Areca RAID card.

arc-1210s.jpg

Now I’m posting my Cacti templates and script to get these values so anyone can create this graph.

Download

Bug in HP1800-8G switch with 64-bit SNMP

September4

HP 1800 8GWhen I recently switched to Cacti for graphing my network, I ran some network speed tests and noticed that the peak of the graph did not correspond with the actual network traffic.

The peak of the graph topped out at 140Mbit while I’d been transferring data at around 600Mbit. It turns out that this is a limitation of 32-bit counters that overflow after 5 minutes.

So I decided to switch to 64-bit counters in Cacti. I ran my tests again and this time my graphs were a total mess. According to the graph I’d transferred multiple terrabytes of data in just 5 minutes.

After some googling I found out that this is a bug in the HP1800-8G. That report is nearly a year old and several firmwares have been released for the HP1800-8G since then, all with the same bug.

So I’ve sent an email to HP to make them aware of this bug, I even received a response:

Dear Customer,

Thank you for using Hewlett Packard Customer Service.

This info has been send to the division and in a later Firmware update this issue will be adressed
unfortunatly there is no timeframe known for this fix yet.

Best Regards,

Hewlett Packard Customer Service

Doesn’t sound very convincing, but I hope the next firmware release fixes this annoying bug.

Migrating to Cacti

August28

My previous post about getting the temperatures of disks connected to an Areca raid array already noted that MRTG can only handle two datasources in a single graph.

With 5 disks in a system, this would force me to create 3 graphs, or 1 graph with the temperatures of the 4 disks connected to the RAID array averaged into a single line.

I’ve always wanted to move from MRTG to RRDtool, because RRDtool can handle multiple datasources per graph, and has more options.

However, I found RRDtool very hard to configure compared to MRTG. So I went looking for an alternative.

Cacti is a front-end for RRDtool, which makes it easier to create nice graphs. If you just want to graph routers, it’s even easier to configure than MRTG. But if you like to have custom stats, like the Areca HDD temperatures, it takes a little more work.
Cacti has some nice guides on how to create graphs and new input methods on their site, but even with those it took me quite some time to create my first graph.

By now I’ve migrated all my graphs from my personal MRTG page to Cacti

HDD temperatures

Areca HDD temperature in MRTG

August7

I’ve been running my Areca RAID array for a few months now and I’m very pleased with it. The only thing that was bothering me was the lack of MRTG graphs for the attached disks.
The disk temperature is an important thing to monitor, because as Google pointed out, a high disk temperature has a significant effect on drive failure.

HDD temperaturesAreca has made some excellent tools available to monitor your array and attached disks. For example, Areca’s web interface can show you all the disk temperatures.

In Areca’s web interface you have total control over your RAID array. You can add/remove disks, create new arrays and do a check on existing arrays.

But it’s annoying to have to log in to this web interface just to check the temperatures of the disks. Also, it doesn’t come with nice graphs and history information. It just shows the current temperatures.

hddtemp-day.png

Areca has also made a CLI utility. Using this utility you can do the same things as in the web interface. I’ve used the CLI utility to generate the data needed by MRTG. MRTG can only handle 2 datasources in one graph. Having 5 disks total (1 bootdisk, 4 RAID member disks), I would need 3 graphs to monitor the disks. So I decided to create a little BASH script that would take the temperature of the bootdisk, and the average temperature of the 4 RAID disks and feed this to MRTG.

« Older EntriesNewer Entries »