Blogger.create { :name =>'Matt Aimonetti',
:location => 'San Diego, Ca',
:email => mattaimonetti AT gmail.com,
:linkedin => Matt's Linkedin page,
:recommend_me => HERE,
:contractor => true}

Rails or Merb, what's best for you?

Written by matt on April 10th, 2008

If you follow my blog, you already know what Merb is.

I love Rails and I truly believe it has changed web development. At least it has changed the way I do web development.

But Merb looks slick, apparently is way faster than Rails, and has less "fluff" and less magic.

Now that we are getting really close to a Merb 1.0 (scheduled for Rails Conf '08) it's time to evaluate if Merb is the good choice for some of my clients' projects.

However, according to Merb's author, Ezra, at MountainWest RubyConf 2008, Rails will get you there faster. In a client's case, they don't need to build a huge app but need a lot of speed and the ability to easily handle a heavy load right away without using caching. Also most of the traffic will go through an API so we won't have to manage too many views.

Let's see how fast Merb really is.

To test Merb's speed, I built the very same prototype using Merb 0.9.2 and Rails Edge (pre 2.1). Both apps use ActiveRecord and are connected to a UTF8 MySQL database, both apps have exactly the same views. (Note that Merb would run way faster using DataMapper, but I don't feel that DM 0.9x is production ready yet, also, using a rack handler would certainly be way faster but my goal was really to compare ActionPack vs Merb.)

Both apps use the same ActiveRecord class, their controllers are a bit different but basically do the same thing.

Here is what was tested:

  • The Merb/Rails app should receive a GET request with a JSON object in the query.

  • The Merb/Rails app should route the request to a controller and pass the JSON object to an AR class.

  • The AR class should parse the JSON object (which contains an array of objects), extract each object, and try to find them in the database using one of the attributes. If the object isn't found, it should be created, otherwise it should return the AR object. The amount of hits should be incremented by 1 and the object should be saved back to the database.

  • A simple HTML view should be rendered

Quick Merb benchmark

merb

I setup Merb to run locally on my MacBook 2.16Ghz Core Duo 2, 2Gb Ram. To test the raw performance, Merb is started in production mode.

I then used httperf to make 10000 connections to the server at a rate of 500 (--rate=500 --send-buffer=4096 --recv-buffer=16384 --num-conns=10000 --num-calls=1)

Here are the results:

Maximum connect burst length: 29
Total: connections 4377 requests 4221 replies 2932 test-duration 41.629 s
Connection rate: 105.1 conn/s (9.5 ms/conn, <=1022 concurrent connections)
Connection time [ms]: min 41.0 avg 1920.4 max 35390.8 median 898.5 stddev 4887.3
Connection time [ms]: connect 2118.1
Connection length [replies/conn]: 1.000

Request rate: 101.4 req/s (9.9 ms/req)
Request size [B]: 321.0

*Reply rate [replies/s]: min 0.0 avg 73.3 max 143.0 stddev 65.8 (8 samples)*
Reply time [ms]: response 809.0 transfer 18.1
Reply size [B]: header 121.0 content 557.0 footer 0.0 (total 678.0)
*Reply status: 1xx=0 2xx=2932 3xx=0 4xx=0 5xx=0*

CPU time [s]: user 0.35 system 36.54 (user 0.8% system 87.8% total 88.6%)
Net I/O: 78.4 KB/s (0.6*10^6 bps)

Errors: total 7068 client-timo 0 socket-timo 0 connrefused 0 connreset 1445
Errors: fd-unavail 5623 addrunavail 0 ftab-full 0 other 0

What we care about is the reply rate/s. We have an average of 73.3 requests per second with a standard deviation of 65.8 using 8 samples.

We also make sure that all the replies were successful. (status == 2xx)

I also checked the database, made sure my AR object was created and that the hits were increased. AR object hits: 2932, which matches the amount of replies reported by httperf.

We don't care so much about the rest of the httperf. Let's move on to the Rails benchmark.


Quick Rails benchmark

rails

Rails is set the same way, running locally in production mode, same httperf settings.

Here are the results:

Maximum connect burst length: 44

Total: connections 2923 requests 2825 replies 1672 test-duration 37.418 s

Connection rate: 78.1 conn/s (12.8 ms/conn, <=1022 concurrent connections)
Connection time [ms]: min 382.7 avg 5635.4 max 36384.5 median 1887.5 stddev 10103.1
Connection time [ms]: connect 3631.2
Connection length [replies/conn]: 1.000

Request rate: 75.5 req/s (13.2 ms/req)
Request size [B]: 319.0

*Reply rate [replies/s]: min 0.0 avg 43.4 max 75.2 stddev 30.8 (7 samples)*
Reply time [ms]: response 1568.1 transfer 36.7
Reply size [B]: header 471.0 content 581.0 footer 0.0 (total 1052.0)
*Reply status: 1xx=0 2xx=1672 3xx=0 4xx=0 5xx=0*

CPU time [s]: user 0.25 system 31.31 (user 0.7% system 83.7% total 84.4%)
Net I/O: 69.4 KB/s (0.6*10^6 bps)

DB hits: 1672

First thing, the database object was created properly and the hits incremented to 1672 which matches the amount of replies reported by httperf.

Then, we notice that on this test, we only got 7 samples, that's more than enough though. The standard deviation is 30.8 which is better than Merb's 65.8. That means that in our benchmarks, the reply speed difference in Merb's requests was bigger than Rails'. Not a big deal, this is not a scientific test but it's good to acknowledge it.

What we really care about is the average reply rate: 43.4

Let's also note that all the replies had a 2xx status, so everything went well.

Results

Based on this really basic benchmark, my Merb app had an average reply rate of 73.3 requests per second against Rails' 43.4 requests per second.

That means that in this very specific case,

Merb is 69% faster than Rails! Sexy!

In other words, my Merb prototype could handle 69% more requests than the Rails prototype in the same amount of time.

I heard people reporting than Merb was 3 to 5 times faster than Rails. Honestly, it really depends on what you do. By using ActiveRecord on both prototypes, I limited the speed difference since AR is not multithread and therefore Merb can't run as fast as it would using Sequel or DataMapper. By actually hitting the database on every single request, I also made sure to really compare ActionPack vs Merb.

Conclusion

The conclusion is simple, I recommended that my client go with Merb. Merb 1.0 is almost ready, the public API has been frozen. My client needs speed and simplicity. Using Merb I get exactly what I need and nothing more. Actually, we'll probably increase the performance by writing a rack handler and bypassing the entire framework for API calls (that should be wicked fast!). Also, as soon as DataMapper becomes production ready, we'll switch to DM and should get way better performance!

Am I suggesting to give up Rails and switch to Merb? Absolutely not! First off, Merb is a "lower level" framework. It requires a deeper understanding of Web Development in general and being more than just 'acquainted' with the Ruby language. So, unless you are an advanced developer or have time to learn, I would suggest to keep on using Rails (start using Merb on personal projects, it's a perfect way of learning). If you have a lot of views and/or use loads of AJAX, RJS, built-in helpers, you probably want to stick to Rails and start looking at how you can do all of that from scratch. By default Rails uses nasty helpers that create inline javascript, and is something you really want to avoid. RJS is fun, but it goes against Merb's philosophy, so you need to make sure you can live without it (note that you can reproduce the same behavior in Merb rendering JS, it just requries more work). If you rely a lot of Rails plugins, you might want to delay your switch, Merb is pretty new and doesn't have a mass-load of plugins yet.

Finally, Merb doesn't have a lot of documentation and changed a lot when 0.9 got released. To understand how Merb works, you will need to go through the source code, specs, Google, and ask on the Merb IRC channel.

It turns out that in our case we have experienced developers, a great need for speed, not too many views and are following Merb's development really closely . I honestly think it's the best choice for my client and I'm excited they accepted to use Merb.

Merb is addressing different issues than Rails and doing it well. I think there is a bright future for Merb. And don't even think that Rails is going away, that won't happen anytime soon!

Recently, Sony Playstation even posted a job post looking for a Rails/Merb developer. This is very promising for the Merb community!



Comments

  • malcontent on 10 Apr 01:31

    do the same thing with ramaze and report the result

  • ste on 10 Apr 02:18

    Are you sure about AR not being threadsafe? I thought the thread-safety offender in Rails was ActionController, not AR. Anyway, there is one thing or two that Rails could learn from Merb; the first that comes to my mind is the double level of abstraction for controllers, which leads to a clean and flexible class structure (I'm thinking about ActionMailer and components...)

  • Lon on 10 Apr 03:11

    I have been playing with Merb since .4, porting small projects and comparing differences. At this point 1.0 can not come fast enough.

    The flexibility, speed, lower memory requirements and modular architecture make it a tasty treat that is truly less filling.

  • Ben on 10 Apr 03:14

    I'm also interested in a ramaze benchmark.

  • Jon Wood on 10 Apr 03:38

    ActiveRecord is thread safe - just set config.activerecord.allowconcurrency in environment.rb (that maps to ActiveRecord::Base.allow_concurrency)

    After that you can quite happily use AR from as many threads as you feel like - I'm using it at the moment for a Rails app using DRb for long running tasks.

  • teki on 10 Apr 05:08

    This one tells a different story: http://work.rowanhick.com/2008/02/12/how-to-avoid-hanging-yourself-with-rails/

  • Matt Aimonetti on 10 Apr 09:32

    @Jon Wood. Many people (including Ezra) have reported weirdness happening when forcing AR to allow concurrency.Apparently sometimes you get records in result sets that come from other threads. People like Evan Phoenix and Wilson Bilkovich (Rubinius team) also recommend not to set AR this way since you have to manually close connections if you turn it on, and there's no cap on how many connections it will make. (it starts one connection per thread)

    @malcontent & @ben I'm sorry but I'm running out of time, Ramaze sounds interesting but since I'm benchmarking for a client's project I wanted to keep my tests to frameworks I believe will get enough momentum. If I find some time later on, I'll be glad to run the same test.

  • Mathijs Kwik on 10 Apr 12:16

    All I read about merb is only about performance, The projects I'm working on with rails aren't high-traffic. Performance issues almost never arise, and when they do, some simple caching does the trick.

    Are there any other good reasons to jump to merb except for performance?

  • Matt Aimonetti on 10 Apr 14:02

    @Mathijs Not really, at least not at the moment. If you are familiar with Rails and happy with it, you should stick to it and re evaluate after 1.0 gets released.

  • Waqas on 10 Apr 22:57

    Doesn't Merb contain 69% less magic than Rails? Merb is just a skeleton yet.

  • Thomas on 11 Apr 04:21

    Hi,

    Your benchmark is completely flawed. Check your figures better next time.

    You are making 10000 connections, in Merb's case you are getting only 2932 replies and 7068 errors. I don't know where you saw that all response were 200, that is not true. Same for Rails.

    Setting the rate to 500 and testing on your local machine, is a nonsense, your computer is uncapable of sustaining such throughput, so once again your benchmark is flawed.

    It seems you have been watching peepcode's screencast because you seem to focus a lot on standard deviation, which is crap. Next time use ApacheBench, and take a look at the time taken for each request,you will see that some requests take like 20-30s to happen, even if the request succeeds, 20s for serving a request to a visitor is unacceptable. I consider anything above 2s to be a failed request.

    I have made benchmarks of one of my Rails app against a php equivalent, and it turned out, that php was only 50% faster, or if you prefer, my Rails app is only 33% slower to make it look better. Anyway, as Zed Shaw stated, there is no need to have a super fast website if you have only 3 visitors per day.

    Redo your benchmark from scratch, because currently you are not proving anything at all.

    Best regards,

  • X on 12 Apr 00:31

    Wouldn't one of the advantages of Merb over Rails be the smaller footprint? It can be handy if you're on a small VPS or even on a shared hosting.

  • Pratik on 15 Apr 16:51

    It's completely weird to see benchmark results posted without the benchmark script/application. In fact, you are not even stating which server you are using. It looks like you've tuned your benchmark parameters to be completely unrealistic, such that it helps spread the FUD.

    Pardon my french, but for fuck's sake, stop saying AR is not threadsafe. Not without a piece of code. "Many people ( including Ezra )" -- That's not an explanation. Code speaks louder than people. I completely agree that one connection per thread is not something desired ( and will change soon ), but that does not make AR thread unsafe.

    Apart from that, you seem to be having a lot of misconceptions about ruby threads. For example, if you were using thin for your benchmarks ( or ebb or any event driven server ), thread safety wouldn't come in the picture. Also, multiple ruby threads are slower than running multiple processes.

  • Matt Aimonetti on 15 Apr 22:45

    @thomas and @pratik you are right, this is a very informal benchmark and I'm certainly not an expert.

    Since I did this quick benchmark for a client, I can't really publish the code, but I will try to rewrite the code and publish the benchmark apps so people can look at them and comment on my mistakes.

    @pratik: as mentioned in my post, I was using my macbook to run the tests. Again, my goal was not to provide the community with a scientific comparison but just to give me an idea of the overhead in ActionPack.

    Regarding the threads, I don't and couldn't find any code to prove that AR is currently thread unsafe. However because of the reasons mentioned above, it's my understanding that it's really not recommended to run AR in threadsafe mode. Anyway, I don't think DM is production ready yet so it sounds fair to compare both frameworks using the same ORM.

  • R. Elliott Mason on 10 May 12:16

    I know that Rails is killing my 256 Slice and I am currently in the process of porting my Rails app to Merb. Since Merb can use AR it has been a pretty decent experience. Most people warned me that switching frameworks is suicide but since my models are fat and my controllers are skinny it has been fairly straightforward. I did have to adjust my Upload model since Merb handles uploads differently than Rails, but other than that it's been a breeze.

    The only thing I feel like I'm missing out on is Rails' abundance of view helpers. It is not incredibly fun to have to code my own link_to_if, but it's not time consuming either.

    And I love raising NotFound (as strange as that sounds), because a 404 isn't always because there isn't a route to match the request, it could also be because a record doesn't exist. Why Rails don't got that?

Post a comment