Just what web server should be sitting in front of my Rails application?

July 16, 2007 - by jason

The one you feel comfortable configuring, maintaining and perhaps extending.

That one.

As web server/reverse proxy schizoserverphrenia tends to sweep through the Rails community from time to time, I see questions of which is “best” so I thought I’d add some numbers here.

These are from April-ish 2006, and were in various places on weblog.textdrive.com and joyeur.

So with

  1. A “Hello World” controller
  2. A good deal of tuning (for example, a fat untuned Apache was 4x slower then my quickly tuned one -> 250ish versus 1000ish)
  3. Comparing similar numbers for FreeBSD and Solaris for various combinations of client, proxy server and rails application servers on absolutely equivalent hardware and all gigabit networking
  4. Using ab, httperf, siege and tsunami and multiple datasets.
  5. Your realization that this is looking at reverse proxy performance only
  6. Knowledge of Apache tuning since it was 0.6
  7. With being around just about every web server, forward proxy cache, reverse proxy cache and load balancer that has been created and either made public, sold or passed among friends.
  8. And having advocated lighttpd use in Rails a “long” time ago as we were getting away from Apache-mod_ruby, and Mark has blabbered about it all as well.

Some representative numbers with FreeBSD client -> FreeBSD web/proxy -> Solaris Rails application server

Litespeed Enterprise 2.1.14 -> Mongrel 0.3.12.4
Concurrency Level: 100
Requests per second: 1008.04 [#/sec] (mean)

Lighttpd 1.4.10 -> Mongrel 0.3.12.4
Concurrency Level: 100
Requests per second: 1010.36 [#/sec] (mean)

I was a fan of apache 1.3’s mod_accel which was by the nginx dude, so 0.3.37 made it in

nginx 0.3.37 -> Mongrel 0.3.12.4
Concurrency Level: 100
Requests per second: 1016.40 [#/sec] (mean)

Zeus -> Mongrel 0.3.12.4
Concurrency Level: 100
Requests per second: 25.07 [#/sec] (mean)

(Zeus still did 1300+ req/sec on static files with the same configuration).

Apache 2.2 worker (with mod proxy balancer) -> Mongrel 0.3.12.4
Concurrency Level: 100
Complete requests: 10000
Requests per second: 1452.23 [#/sec] (mean)

Apache 2.0 using the prefork MPM, only mod_proxy
Concurrency Level: 100
Complete requests: 10000
Requests per second: 1070.59 [#/sec] (mean)

What’s the lesson I learned from this?

That when you spend a while tuning each, digging through their code and instrumenting, there is not a significant difference between these when it comes their ability to be a reverse proxy server in terms of throughput. There is a significant difference in what one does “out of the box” and there are more significant differences in their abilities to serve static files and in their memory footprints.

And there was one thing that became very clear though through all of them and that was differences in their horizontal scalability. Covered here

What do I like as the current?

Dynamic Rails Parts

F5 BIG-IPs -> Varnish -> F5 BIG-IPs -> Mongrel

Varnish by the way is a fine piece of software mainly written by the incredible PHK and with the VCL’ed PURGE function in which you can programmatically clear things from the cache (ticket). Did you hear what I said? You can have this very fast cache do all the caching for your Rails applications (or anything for that matter), and when something is updated in your application, you can actually have it ping the cache with a

"PURGE /images/207/123/52db760df37da63a1c9d94a1be6fcf6f.jpg HTTP/1.0"

Nice.

Mongrel has been good, but right now JRuby-Glassfish is doing a bit of a siren’s song because of some places it can help in the backend (and it also happens to be fast).

Static Non-Rails Parts

Level3 CDN -> F5 BIG-IPs -> Varnish -> Nginx

A CDN is a good thing, the F5’s are there because they’re faster than Varnish, and Varnish is faster than nginx (and also not a web server).

:

Sign up now for Instant Cloud Access Get Started