Labels: eventmachine , Ocaml , ruby 1.9.1 , unicycle
If you are not following Mauricio Fernandez's blog then please do yourself a favor and subscribe to it. Mauricio's writings are very interesting and informative. In one of his posts Mauricio gives a record of re-implementing his blog in OCaml using the OCsigen (webserver + framework) library. Mauricio did some benchmarking for the OCsigen environment against Rails and even a C fastcgi implementation. Naturally one would expect that OCaml will be orders of magnitude faster than Ruby. But the benchmark showed really abysmal performance for Rail vs. OCsigen. We are talking 260 request per second vs. 4500 requests per second for a single process test! That's north of 20X difference! I decided that Ruby can do better.
Looking at what OCsigen offers revealed that Rails is an overkill in comparison. I thought that for Ruby a nice alternative can be the mystery webserver + framework called unicycle (never heard of it? you don't know what you're missing). Since OCsigen offers LWt (a light weight cooperative threading library) at its core for concurrency I added a fiber wrapper to Unicycle's request processing path so that we get a similar overhead (the testing was done using Ruby 1.9.1).
Here are my results:
Hello World - Unicycle, Single Process: 7378 requests/second
Please note that this is running on my Intel Mobile Core 2 Duo 2.0 GHZ processor vs. the 3GHZ desktop AMD Athlon64 that was used for the original tests (it should be roughly 50% faster than my mobile core2).
I decided to take it further still. Mauricio mentioned that he was able to get performance above 2000 req/s from OCsigen when benchmarking the blog page that we are discussing here. So I created a sqlite database (he mentioned somewhere that he is using sqlite) and inserted the same blog entry (with very little modifications) in a structured manner. I didn't bother with comments though (out of being lazy). Sequel was used to connect and fetch the record from the database and an rhtml template that is rendered using Erubis. The result was a page very similar to the original blog post. ApacheBench was used to benchmark the page.
Unicyle + Fibers + Sequel (Sqlite) + Erubis, Single Process: 1296 requests/second
During the time of testing the Unicycle process was between 13MB and 21MB (that's 3x to 4x the size of the OCsigen process)
Considering that the components found in any laptop are usually inferior to their desktop counter parts I believe this at least equals the figure reported for OCsigen's performance.
How can Ruby achieve such performance? By careful selection of components:
First off, Ruby 1.9.1, everybody should start using it for their next project. It is much faster and much easier on memory
Unicycle is built atop EventMachine and the EventMachine HTTP Server. Both are C based speed demons. Unicycle itself is a minimal framework that doesn't attempt to be so smart.
Erubis is a nice surprise. Pure Ruby and decently fast are not commonly found together but kudos to the authors of Erubis, they somehow did it.
Conclusion
Ruby is faster the OCaml. Wrong! OCaml is a lot faster than Ruby. But thanks to hard work by some prominent Rubyists you can have a Ruby setup that performs decently enough to make you proud.
Looking at what OCsigen offers revealed that Rails is an overkill in comparison. I thought that for Ruby a nice alternative can be the mystery webserver + framework called unicycle (never heard of it? you don't know what you're missing). Since OCsigen offers LWt (a light weight cooperative threading library) at its core for concurrency I added a fiber wrapper to Unicycle's request processing path so that we get a similar overhead (the testing was done using Ruby 1.9.1).
Here are my results:
Hello World - Unicycle, Single Process: 7378 requests/second
Please note that this is running on my Intel Mobile Core 2 Duo 2.0 GHZ processor vs. the 3GHZ desktop AMD Athlon64 that was used for the original tests (it should be roughly 50% faster than my mobile core2).
I decided to take it further still. Mauricio mentioned that he was able to get performance above 2000 req/s from OCsigen when benchmarking the blog page that we are discussing here. So I created a sqlite database (he mentioned somewhere that he is using sqlite) and inserted the same blog entry (with very little modifications) in a structured manner. I didn't bother with comments though (out of being lazy). Sequel was used to connect and fetch the record from the database and an rhtml template that is rendered using Erubis. The result was a page very similar to the original blog post. ApacheBench was used to benchmark the page.
Unicyle + Fibers + Sequel (Sqlite) + Erubis, Single Process: 1296 requests/second
During the time of testing the Unicycle process was between 13MB and 21MB (that's 3x to 4x the size of the OCsigen process)
Considering that the components found in any laptop are usually inferior to their desktop counter parts I believe this at least equals the figure reported for OCsigen's performance.
How can Ruby achieve such performance? By careful selection of components:
First off, Ruby 1.9.1, everybody should start using it for their next project. It is much faster and much easier on memory
Unicycle is built atop EventMachine and the EventMachine HTTP Server. Both are C based speed demons. Unicycle itself is a minimal framework that doesn't attempt to be so smart.
Erubis is a nice surprise. Pure Ruby and decently fast are not commonly found together but kudos to the authors of Erubis, they somehow did it.
Conclusion
Ruby is faster the OCaml. Wrong! OCaml is a lot faster than Ruby. But thanks to hard work by some prominent Rubyists you can have a Ruby setup that performs decently enough to make you proud.
I'm a little fuzzy on the Unicyle bit of interacting with rails, but ruby 1.9 and erubis integration should be all good.
Excellent post, thanks.
Where's a link for unicycle?
@6moon: Unicycle has nothing to do with Rails. It is a stand alone framework+server that should be good for a multitude of apps (the router is very limited in flexibility though)
@anonymous: here you go http://groups.google.com/group/eventmachine/browse_thread/thread/4c178b9f8f31f9d9?pli=1 but beware that references for md5 need to be removed before it works with stock ruby 1.9.1
Why not create c00l ruby script like:
system('apachectl start')
and say that ruby is fast?
You compare c library (eventmachine) vs ocaml. Where is ruby? Webrick?
Fast enough for many needs, but that's beside the point! :P
I explicitly stated that OCamls is a lot faster than Ruby. My point though is that the Ruby toolkit has options that can offer decent performance.