Since the initial release of the teaser screencast, a lot of people have asked about Passenger’s (a.k.a. mod_rails) performance compared to Mongrel and Thin. Here’s the benchmark that you’ve all been waiting for.
In this benchmark, we compare the following software:
System specification:
- Intel Core 2 Duo, T5300 @ 1.73GHz
- 2 GB RAM
- Ubuntu Linux 7.10
- Apache 2.2.4 (Ubuntu package)
- Ruby 1.8.6 (Ubuntu package)
Test applications:
- Typo 5.0.3. This is an out-of-the-box setup with only a hello world post. Uses semi-static caching.
- Petstore revision 360, an application that the JRuby guys use for benchmarking. At first it wouldn’t start in Passenger because of a bug Petstore: they forgot to add
require 'forwardable' in app/models/cart_items.rb. I added this line myself.
- Eldorado 0.9.1. This is an out-of-the-box setup with only a single forum and a single post added.
Typo and Eldorado both use SQLite 3. Petstore uses MySQL, because for some reason Petstore performs very badly when SQLite 3 is used.
People have also recommended Lovd By Less as test application, but I couldn’t get it working (database setup failed).
The applications, when served by Passenger, are setup at the following test domains:
- http://typo.test/
- http://petstore.test/
- http://eldorado.test/
Both the Mongrel cluster and the Thin cluster are setup at http://mongrel_cluster.test/. (Only either Mongrel or Thin is running during the benchmark, not both at the same time.)
And of course, we always use the production environment.
Backend configuration:
Benchmark: Mongrel clusters
First we benchmark Typo served by Mongrel clusters. Because the actual application code is loaded by Mongrel during the first request, we do not want to count the first request’s time. So we run the following command to “warm up” the Mongrels, and discard its result:
ab -n 1000 -c 100 http://mongrel_cluster.test/
Next, we test 10,000 requests with 100 concurrent users:
ab -n 10000 -c 100 http://mongrel_cluster.test/
Result:
Concurrency Level: 100
Time taken for tests: 32.628480 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 54890000 bytes
HTML transferred: 51480000 bytes
Requests per second: 306.48 [#/sec] (mean)
Time per request: 326.285 [ms] (mean)
Time per request: 3.263 [ms] (mean, across all concurrent requests)
Transfer rate: 1642.83 [Kbytes/sec] received
We repeat these steps Petstore and Eldorado.
Petstore:
(for Petstore we benchmark the URI “/shop/viewCategory.shtml?category=DOGS” because it’s written in the INSTALL file)
Concurrency Level: 100
Time taken for tests: 109.786026 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 40750000 bytes
HTML transferred: 37680000 bytes
Requests per second: 91.09 [#/sec] (mean)
Time per request: 1097.860 [ms] (mean)
Time per request: 10.979 [ms] (mean, across all concurrent requests)
Transfer rate: 362.47 [Kbytes/sec] received
Eldorado:
Concurrency Level: 100
Time taken for tests: 70.889388 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 41130000 bytes
HTML transferred: 35530000 bytes
Requests per second: 141.06 [#/sec] (mean)
Time per request: 708.894 [ms] (mean)
Time per request: 7.089 [ms] (mean, across all concurrent requests)
Transfer rate: 566.60 [Kbytes/sec] received
Benchmark: Thin clusters
The benchmarking steps for Thin are the same.
Typo:
Concurrency Level: 100
Time taken for tests: 25.795470 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 54910000 bytes
HTML transferred: 51480000 bytes
Requests per second: 387.66 [#/sec] (mean)
Time per request: 257.955 [ms] (mean)
Time per request: 2.580 [ms] (mean, across all concurrent requests)
Transfer rate: 2078.78 [Kbytes/sec] received
Petstore:
(for Petstore we benchmark the URI “/shop/viewCategory.shtml?category=DOGS” because it’s written in the INSTALL file)
Concurrency Level: 100
Time taken for tests: 96.874308 seconds
Complete requests: 10000
Failed requests: 42
(Connect: 0, Length: 42, Exceptions: 0)
Write errors: 0
Non-2xx responses: 42
Total transferred: 40630350 bytes
HTML transferred: 37547028 bytes
Requests per second: 103.23 [#/sec] (mean)
Time per request: 968.743 [ms] (mean)
Time per request: 9.687 [ms] (mean, across all concurrent requests)
Transfer rate: 409.58 [Kbytes/sec] received
Eldorado:
Concurrency Level: 100
Time taken for tests: 71.311031 seconds
Complete requests: 10000
Failed requests: 5
(Connect: 0, Length: 5, Exceptions: 0)
Write errors: 0
Non-2xx responses: 5
Total transferred: 41137070 bytes
HTML transferred: 35518568 bytes
Requests per second: 140.23 [#/sec] (mean)
Time per request: 713.110 [ms] (mean)
Time per request: 7.131 [ms] (mean, across all concurrent requests)
Transfer rate: 563.34 [Kbytes/sec] received
Benchmark: Passenger
The benchmarking steps for Passenger are the same.
Typo:
Concurrency Level: 100
Time taken for tests: 25.131980 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 55200000 bytes
HTML transferred: 51260000 bytes
Requests per second: 397.90 [#/sec] (mean)
Time per request: 251.320 [ms] (mean)
Time per request: 2.513 [ms] (mean, across all concurrent requests)
Transfer rate: 2144.92 [Kbytes/sec] received
Petstore:
(for Petstore we benchmark the URI “/shop/viewCategory.shtml?category=DOGS” because it’s written in the INSTALL file)
Concurrency Level: 100
Time taken for tests: 104.428742 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 40300000 bytes
HTML transferred: 36700000 bytes
Requests per second: 95.76 [#/sec] (mean)
Time per request: 1044.287 [ms] (mean)
Time per request: 10.443 [ms] (mean, across all concurrent requests)
Transfer rate: 376.86 [Kbytes/sec] received
Eldorado:
Concurrency Level: 100
Time taken for tests: 72.587018 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 41660000 bytes
HTML transferred: 35530000 bytes
Requests per second: 137.77 [#/sec] (mean)
Time per request: 725.870 [ms] (mean)
Time per request: 7.259 [ms] (mean, across all concurrent requests)
Transfer rate: 560.47 [Kbytes/sec] received
Summary
Here’s a nice summary of the requests per second, in a table and in a graph:
|
Typo |
Petstore |
Eldorado |
| Mongrel |
306.48 |
91.09 |
141.06 |
| Thin |
387.66 |
103.23 |
140.23 |
| Passenger |
397.90 |
95.60 |
139.27 |

Conclusion
I was pleasently surprised by the results. During Passenger’s development, our performance baseline was Mongrel behind mod_proxy. According to earlier (simple and naive) tests, Passenger performed similar to Mongrel. I expected Thin to be a bit faster than Passenger. These new benchmarks however suggest Passenger is faster than Mongrel, and is on par with Thin.
But you know what they say: there are lies, damn lies, and statistics. Your hardware and software is different, so if you benchmark it yourself, you’re likely to get (slightly?) different results.