Introduction to Merb

Posted by Luke Francl
on Thursday, October 09

One of the most enduringly popular articles on Rail Spikes is my introduction to Merb from back in April, 2007(!): Merb (and why you potentially should care).

pageviews graph for Merb article

Obviously Merb has changed a lot since that article was written, so it is completely out of date (I think it was about Merb 0.4 or something like that).

Fortunately, Matt Todd (who I met at RubyFringe—look for his talk on InfoQ one of these months) has a much better look at where the Merb framework is today, as it approaches its 1.0 release at MerbCamp this weekend. Matt presented this at AltRUG yesterday.

Check it out. (Also, you may be interested in Jon’s interview with Ezra Zygmuntowicz from back in June.)

Where Merb is, and where it's going: interview with Ezra Zygmuntowicz

Posted by Jon
on Thursday, June 05

Merb has come along way since Luke first examined it here over a year ago. The philosophy remains the same: “All you need. Nil you don’t.” But the implementation has changed a bit, and it is far more mature.

Like Rails, Merb is a MVC web framework written in Ruby. Unlike Rails, Merb doesn’t tell you what ORM to use – you can use ActiveRecord, but DataMapper and Sequel are a bit more in line with the Merb philosophy. Similarly, Merb supports several Javascript libraries and templating languages, and doesn’t recommend one over another. Merb strikes a balance between Rails (large and full-featured) and Camping or Sinatra (tiny), but it is closer to Rails; one gets the sense that a large, complex site could be reasonably maintainable in Merb, unlike Camping or Sinatra.

Merb got a lot of attention at RailsConf this weekend, and will probably get even more at RubyFringe and RubyConf, and it seemed like time to review it again, about a year after our first look. Ezra Zygmuntowicz, creator of Merb, was kind enough to give us an interview.

Rail Spikes: How much production use has Merb seen so far?

Ezra: A lot. We have about 40 or so Merb apps hosted here at EngineYard. A few of them are doing 2-8 million pageviews/day with Merb rock solid at 35Mb ram on a 64 bit system.

Rail Spikes: Merb is thread-safe, unlike Rails. What advantages does thread-safety bring to Merb?

Ezra: It allows for long requests to not block the process, effectively letting multiple requests get served at once. This can drastically reduce the latency any one user gets because requests do not get backed up behind longer requests waiting for their chance to run.

Rail Spikes: So do Merb apps typically use a single mongrel/thin instance, or multiple instances?

Ezra: Merb apps still typically use multiple processes, but they require less processes then an equivalent Rails app by far.

Rail Spikes: Is the only advantage of multiple instances to make use of multiple CPU cores? And will a natively threaded Ruby implementation allow us to use a single app server per box?

Ezra: Yes, it is to use multiple cores and to spread out the load. Natively threaded ruby implementation will allow us to use much fewer processes, but running an app out of a single process is still a bad idea in case the instance crashes, so load balancing over a few processes helps increase uptime if there is an issue with any single process.

Rail Spikes: Does one need to use a thread-safe ORM like DataMapper to take advantage of this, or does ActiveRecord::Base.allow_concurrency = true work just as well?

Ezra: Yes – you need a thread safe ORM like DataMapper or Sequel. ActiveRecord::Base.allow_concurreny = true does not work well and should be avoided for now.

Rail Spikes: Merb has long been agnostic about things like ORM, templating language, and Javascript/ajax libraries. Will that continue, or will Merb ever “prefer” one systems over others? And is Merb test framework agnostic, or does it prefer rspec?

Ezra: It will continue as much as possible. We do favor rspec over test/unit so that bias does show a bit. I also personally prefer DataMapper as my ORM. But Merb will definitely remain ORM agnostic as I think that going forward there are going to be all kinds of interesting non-relational data stores to build web apps on. Merb will be right there at the forefront easily using any new persistence layer that pops up.

Rail Spikes: You’ve written that Merb and Rails can get along. Would you use Rails instead of Merb for some projects? If so, what and why?

Ezra: Rails is a more complete end to end solution; there is a large ecosystem and plugins for almost everything. But Rails is also a large bloated codebase so if you want to step outside the golden path of the framework you will often run away screaming. ;) Merb is more of a platform for you to build whatever it is you want on it. The framework code is simple and to the point so it is very easy to extend and bend Merb to your will when you run into a problem that the framework has not thought of or dealt with before. In the end I think this makes for a more scalable framework for serious hackers to build interesting new stuff I have never thought of.

So Rails may get you up and running quicker, but Merb will scale further as your application needs to go “off the rails” so to speak.

Rail Spikes: Beyond the docs, what is the best resource for a Rails developer looking to learn Merb?

Ezra: There is a Merb PeepCode that is pretty good, and the merbunity.com site is good. The Merb wiki is starting to have a lot of information. There is a book coming out soon from Manning called Merb in Action, written mostly by Michale Ivey and Yehuda Katz with me as an advisor/proofreader.

Rail Spikes: Can you point us to any speed benchmarks?

Ezra: I don’t have any prerolled benchmarks at this point. But I can say that in general Merb’s routing, dispatching, request parsing, filters and rendering are dramatically faster then ActionPack. I encourage folks to run their own benchmarks as microbenchmarks are rarely helpful.

In general Merb can serve a hello world action at 2500req/sec on ebb and can serve a simple template wrapped in a layout action at 1700req/sec or so on a Macbook Pro.

Rail Spikes: What is the 12-month plan for Merb?

Ezra: Merb 1.0 will be released sometime this summer along with DataMapper 1.0. I don’t have a long term 12 month plan for Merb, but I think that 1.0 will be a super solid platform for folks to build on top of. I don’t believe in having Merb become a kitchen sink framework, I’d rather see a tight/fast/documented core and let everything else be plugins so we don’t end up bloating the core framework.

Rail Spikes: Thanks!

Merb (and why you potentially should care)

Posted by Luke Francl
on Sunday, April 01

Update: We’ve posted a new and updated Merb article in the form of an interview with Ezra. This original article was presented at the March 27, 2007 Ruby Users of Minnesota meeting. You may also download the presentation (PDF, 100K).

Merb is “Mongrel + ERB,” written by Ezra Zygmuntowicz of Engine Yard.

I must admit that when I first heard of Merb, I thought, “Ah, PHP is making a comeback.” But Merb is actually a small Model-View-Controller framework similar to Rails in many ways, but with some features that make it superior for some tasks, like handling file uploads.

Key features in Merb:

1. Merb is thread-safe

Merb does not use ActionPack which is the main offender of thread unsafety in Rails. ActionPack is the Rails controller and view system. Merb implements its own controllers, and doesn’t have a whole lot in terms of view helpers.

Note: Ruby uses “green” threads, which are implemented inside the Ruby interpreter, not at the operating system level. To take advantage of multi-CPU machines, you will need to run (at least) one ruby process per CPU.

2. Merb uses Erubis for embedded Ruby

Erubis is a re-implementation of ERB that is significatnly faster. Erubis is 3 times faster than ERB, and even 10% faster than eRuby, which is a C implementation of ERB!

Note: Erubis is close to being fully supported in Rails. Perhaps in the next release…?

3. Merb does not use CGI.rb

CGI.rb is quite slow and very processor intensive, especially for parsing multipart form uploads. Merb doesn’t use it. However, Merb does use regular expression matching to parse requests, so it’s possible it could suffer from the same problems; I haven’t investigated this myself, though.

This last feature is critical. You may have heard that Rails blocks while handling file uploads. When you’re using Mongrel, this is not strictly true. Yes, Mongrel blocks while running a Rails request. But Mongrel pre-buffers file uploads, and hands the entire file to Rails.

[File] upload doesn’t block Rails actions going on, when you finally pass this to Rails you’ll block that Mongrel process while cgi.rb is going.

This is why you should make a separate Mongrel handler to do all of your upload processing and file preparation before you pass the fully cooked stuff to Rails. Mongrel running cgi.rb in a thread is much more efficient than Rails running cgi.rb inside a lock.

Zed Shaw (emphasis mine)

Merb is essentially an easier way to write a custom Mongrel upload handler. And as a bonus, it does not use CGI.rb at all.

Do you need Merb?

The short answer is “no.” The longer answer is “not yet.”

We planned on using Merb in a recent project at Slantwise. You know the drill: the customer says the site’s going to be huge, it needs to scale, yadda yadda. We don’t believe in pre-optimizing, but we thought we’d take a look at Merb and see how hard it would be to integrate with a Rails app.

After talking to Ezra about it, we decided not to use Merb—until we need to.

We had fallen under the widely held misconception that Mongrel blocks during file uploads. It doesn’t. So we will load test the application and decide after that if we need more uploads per second.

Installing Merb

Merb is available as a gem. However, development moves fast and you will run into bugs that get fixed in the trunk that aren’t available in the gem. If you decide you need to use Merb, I recommend running off the trunk.

sudo gem install mongrel json erubis archive-tar-minitar rspec -y

svn co http://svn.devjavu.com/merb/trunk merb && cd merb && rake install

(This last command will create a gem from the trunk.)

Then you can generate a new merb app:

merb -g myapp

Merb versus Rails

Merb uses ActiveRecord, so all your favorite features are there. It’s Model-View-Controller so development is similar.

In general, Merb is rougher around the edges than Rails, and documentation is harder to come by and less expansive. This is to be expected, as the framework is a lot newer than Rails with fewer users. But development is ongoing and the mailing list is friendly. There’s also a sample application called MrBlog you can learn from.

Here’s some of what you can expect:

  • Generator scripts are not generally available (there is one for creating a migration).
  • Routing is different (simple but functional, and RESTful routes are available).
  • There are not many view helpers—you write straight ERB most of the time.
  • Don’t forget to call render in your controller actions—Merb doesn’t do it for you.
  • Most configuration is in Ruby rather than YAML.
  • You may run into bugs (file them in Trac).

Merb + Rails

Perhaps more interesting is getting Merb working with your existing Rails app, for example, to handle file uploads and processing.

  • Merb uses ActiveRecord, so you can use your existing data model.
  • If you store your sessions in the database, Merb can piggy-back on the Rails session ID, so you can use your existing authorization mechanism.

In about half a days work, I was able to get Merb loading up my ActiveRecord objects from my Rails project (to avoid code duplication), and get the attachment_fu plugin working.

Use your Rails models in Merb

You can include your Rails models in Merb.

Here’s an example. DIST_ROOT is the Merb root directory. In this example, I’ve installed the Merb app inside the Rails root, so I go down to the Rails root and back up to the model I want.

1
2
3
4

class Item < ActiveRecord::Base
end
require DIST_ROOT + '/../../app/models/item.rb'

Getting ActiveRecord plugins working

Obviously, not all Rails plugins will work with Merb. But a lot of Rails plugins are really just ActiveRecord plugins. Attachment_fu is an example. If attachment_fu worked with Merb, you’d have a simple way to process uploads for your Rails application.

I got attachment_fu working with Merb in an afternoon with a few tweaks to the code. The code’s too ugly to share here, but I can tell you how I did it.

Mostly I had to change how files were required, because Rails does a lot of magic to load plugins. I had to require each file individually. Attachment_fu also relies on the RAILS_ROOT constant. I defined it equal to Merb’s DIST_ROOT.

One change in attachment_fu itself was required.

1
2
3
4
5
6
7
8
9
10
11
12
13

# TODO: Allow it to work with Merb tempfiles too.
def uploaded_data=(file_data)
  return nil if file_data.nil? || file_data.size == 0 
  self.content_type = file_data.content_type
  self.filename     = file_data.original_filename if respond_to?(:filename)
  if file_data.is_a?(StringIO)
    file_data.rewind
    self.temp_data = file_data.read
  else
    self.temp_path    = file_data.path
  end
end

See that TODO? Because Merb doesn’t use CGI.rb, the file_data object is actually a File, and it lacks some methods.

This is pretty easy to work around:

1
2
3
4
5
6
7
8
9
10
11
12
13

def uploaded_data=(file_data)
  return nil if file_data.nil? || file_data.size == 0 
  self.content_type = file_data.content_type if file_data.respond_to?(:content_type)
  self.filename     = file_data.original_filename if respond_to?(:filename) && file_data.respond_to?(:original_filename)
  if file_data.is_a?(StringIO)
    file_data.rewind
    self.temp_data = file_data.read
  else
    self.temp_path    = file_data.path
  end
end

This isn’t ideal (after all, it’d be nice to know the content type and the original file name) but it worked for my demo.

Deploying Merb with Rails

I have not done this myself, but I believe the correct way to do it is to point your load balancer to your Merb app for certain requests—like POSTs to /upload.

The nice thing about this is that you can develop your Rails app as normal. If you find Rails cannot handle the load, you could drop in Merb to handle file uploads and processing at the same URL. The Merb app would handle the upload, then redirect back to your Rails app.

Resources