a weblog
by jordan hollinger
How to deploy a multi-threaded Rails app
Multi-threaded Rails apps have to be the best kept secret in the Rails community. “What do you mean? It’s been discussed at length for years!” Yes, the benefits, drawbacks, and limitations have been. But, JRuby aside, I have never ever seen someone saying “This is how you do it.”
It’s easy to find instructions for turning threaded mode on in Rails. Just comment out config.threadsafe! in config/initializers/production.rb . But that’s only half the story. Normally, Rails has a mutex around request handling, allowing only one at a time. threadsafe! removes that, telling Rails to handle requests concurrently as they come in. But your app server (Passenger, Mongrel, etc.) is what needs to send your app those concurrent requests in threads. Most never will.
Are you sure?
Go ahead, turn threadsafe! on in one of your apps. Then create an action called foo .
...
def foo
n = params[:n].to_i
sleep n
render :text => "I should have taken #{n} seconds!"
end
..
Open a broswer window and pass it ?n=15. Quickly open another window and pass it ?n=2. Window 1 will render in 15 seconds. With config.threadsafe! on, you’d expect Window 2 to finish well before Window 1. But no, Window 2 takes 17 seconds, because it’s waiting on the first request, which is taking 15 seconds. You may have told Rails it’s safe to be threaded, but your app server isn’t threading .
An aside
I will note, as have many others, that Rails thread-safety means little if your gems are not thread-safe or are doing lots of blocking. You’ll have to deal with that on your own. My understanding is that the mysql2 gem used in Rails 3 took care of this for the average app.
Most Rails deployments can’t go multi-threaded, no matter what
Passenger and Unicorn definitely can’t. Most Mongrel deployments can’t or won’t (not sure which). These are all process-based request servers, like Apache, where a process handles only one request at a time. If you want to handle n concurrent requests, you need n copies of your app running. Rainbows! and Zbatery I believe have event-based concurrency, but that is not the same as multi-threading. So what does that leave us?
I got Thin
The only Rack server I’ve found that mentions multi-threading is Thin . It uses EventMachine to handle concurrent requests. Yay! Everything solved, right? Not quite. As is the case with Rainbows! and Zbatery, event-based processing is not the same as multi-threading, and buys config.threadsafed!‘d Rails apps nothing. But Thin does have a threaded mode which can be enabled by passing “—threaded” on the command line or by setting “threaded: true” in your YAML config file. That’s it! Try the above test now, and Window 2 will finish long before Window 1.
Follow this simple bug work-around if you’re using Ruby 1.9.2. Otherwise all your requests could take almost a minute to complete!
You also may want to read my post on Thin config and managment .
Is Thin the only way?
I hope not. If so, that means Rails has an incredibly powerful features that everyone’s excited about, but at the same time, that no one really cares about. Thin is the only multi-threaded Rack server on which I can find any meaningful discussion or documentation (and even that is scant). If you know of another, please let me and everyone else know!
Look into Nginx
To really take advantage of all these multi-threading and asynchronous goings-ons, you should look into dropping Apache and switching to Nginx. In fact if you’re trying to run as efficiently as possible on a VPS, I insist you look into it! There’s plenty out there, but I’d start with a good comparison of the two.

January 28, 2012 at 6:35 AM
My experience when testing thin in multi-threaded mode was that it's performance was terrible. This was a long time ago, so you should do your own testing, I was using apache bench.
On the bright side, both mongrel and webrick are multi-threaded, so try apache-bench against them as well. Rainbows has a threaded mode too.
allot has changed since I initially did my research. 1.9.3 is out now, and has some threading goodness that didn't exist before.
But to answer your question about which ruby webservers are threaded, the ones I mentioned above are, (which is funny since they (with the exception of rainbows) are the oldest). I think it is because in many cases they were written before the threading issues in ruby were widely understood, (and now largely gone in all current versions of the major implementations including mri if you are on the 1.9 series [admittedly you have to pull tricks with 1.9.x like spinning up as many processes as you have cores to get 100% cpu utilization, but this isn't so terrible])