Yehuda Katz is a member of the Ember.js, Ruby on Rails and jQuery Core Teams; he spends his daytime hours at the startup he founded, Tilde Inc.. Yehuda is co-author of best-selling jQuery in Action and Rails 3 in Action. He spends most of his time hacking on open source—his main projects, like Thor, Handlebars and Janus—or traveling the world doing evangelism work. He can be found on Twitter as @wycats and on Github.

Merb Master Process

Apologies for the delay in posting about this. I was enjoying the fantastic Ajax Experience and jQuery Camp out in Boston, where I got a chance to hang with my jQuery compatriots as the huge Microsoft and Nokia announcement broke.

Now that I’m back, I want to talk about the cool new features we’ve been adding to Merb’s server. Let’s take a look at them one at a time:

  • When a Merb server boots up and tries to bind to existing ports, it doesn’t crash. Instead, it waits for each port to become available and binds when they do. As a result, you can start up a new merb, and then gracefully kill the old one. This should make restarting clusters of merbs significantly less painful, and with almost no downtime.
  • Merb’s clusters have been rewritten to take advantage of Ruby Enterprise Edition, which makes it much easier to share memory between workers in a Merb cluster. Using Ruby Enterprise with Merb 1.0 should yield around the same 30% memory improvement that Phusion Passenger yields.
  • Merb clusters are now controlled by a master process, which can be told to gracefully kill all of its children, or reload the application code (but not init.rb or gems). 
  • Sending an INT to the master process (directly or via merb -K all) tells each of the worker processes to gracefully die. 
  • Sending a HUP to the master process tells each of the worker processes to gracefully die, but to start up a new cluster with reloaded code. This bypasses reloading Merb, gems, and init.rb, so the restart is much quicker than doing a full reload. This is also the same internal code used by development mode code-reloading, which has now been made 100% foolproof.
  • Killing a worker process (either via INT, which is graceful, or KILL, which isn’t) will cause a new process to be respawned instantly. We’re talking basically no time at all, since no code needs to be reloaded (the spawner process forks right before binding to a port)

All of these improvements are just harbingers of even more improvements, making Merb’s master process even more powerful and smart.

The most important thing to keep in mind is that Merb has been significantly tuned for Ruby Enterprise, and with regular Ruby, there is a bit of overhead for the master processes. All of the features above will work correctly with standard Ruby, but you’ll get them for free (memory-wise), as well as quite a bit of improved memory overall in a cluster by using Ruby Enterprise.

Please please please check it out.

11 Responses to “Merb Master Process”

Nice stuff Katz!
I’m a bit dubious about claims like “made 100% foolproof” ;)… but I’m happy to hear about the improvements!!!

friggin awesome!!!1!

This is great – it’s refreshing to see software that does the simple things right…

@john it’s just the nature of the new approach. Because we literally wipe all of the state since the original code was loaded (by starting a brand-new process) it’s impossible for state post-file-load to leak back in.

Yay! I was just thinking about this stuff today. Glad to hear it’s making it into Merb finally.

Amazing stuff. Great work.

Just waiting for the port to become available is a great thing. Would be nice to have more servers do that.

I still think “Ruby Enterprise Edition” is a really awkward name, after all the stupid Java Enterprise Edition crap which didn’t help that much in writing web applications… Who comes up with these names?

I agree — totally awesome stuff. Keep up the good work, guys.

Nice! But how do you handle Windows and JRuby compatibility? Do you gracefully fallback to the old method on those platforms?

@Hongli,

This forking functionality is optional and can be turned off explicitly. By default it’s off on Windows, MinGW and JRuby.

Just found this article while setting up new merb clusters. How do you guys deal with pid files? (I’m specifying mine manually with -P /…/log/merb.cluster.%s.pid)

I can’t start up a new cluster when one is already running or I get:
FATAL: Merb is already running on port 4000.
pid file: /…/log/merb.cluster.4000.pid, process id is 12345.

If I remove the pid files first, the new app will start, but when I send a SIGINT to the master of the old cluster, all of my new pid files are deleted when the old cluster exits (even though the files have been recreated/updated)

Leave a Reply

Archives

Categories

Meta