Adding Concurrency to Rails Apps with Unicorn
- Last Updated: February 27, 2013
With support for Node.js, Java, Scala and other multi-threaded languages, Heroku allows you to take full advantage of concurrent request processing and get more performance out of each dyno. Ruby should be no exception.
If you are running Ruby on Rails with Thin, or another single-threaded server, you may be seeing bottlenecks in your application. These servers only process one request at a time and can cause unnecessary queuing. Instead, you can improve performance by choosing a concurrent server such asUnicorn which will make your app faster and make better use of your system resources. In this article we will explore how Unicorn works, how it gives you more processing power, and how to run it on Heroku.
Concurrency and Forking
At the core of Heroku is theUnix Philosophy, and we see this philosphy at work in Unicorn. Unicorn uses the Unix concept offorking to give you more concurrency.
Process forking is a critical component of Unix's design. When a process forks it creates a copy of itself. Unicorn forks multiple OS processes within each dyno to allow a Rails app to support multiple concurrent requests without requiring them to be thread-safe. This means that even if your app is only designed to handle one request at a time, with Unicorn you can handle concurrent connections.
Unicorn leverages the operating system to do most of the heavy lifting when creating and maintaining these forks. Unix-based systems are extremely efficient at forking, and even take advantage ofCopy on Write optimizations that are similar to those in the recently releasedRuby 2.0.
Unicorn on Rails
By running Unicorn in production, you can significantly increase throughput per dyno and avoid or reduce queuing when your app is under load. Unicorn can be difficult to setup and configure, so we’ve providedconfiguration documentation to make it easier to get started.
Let's set up a Rails app to use Unicorn.
Setting up Unicorn
First, add Unicorn to your applicationGemfile:
gem 'unicorn'Run$ bundle install, now you are ready to configure your app to use Unicorn.
Create a configuration file for Unicorn atconfig/unicorn.rb:
$ touch config/unicorn.rbNow we're going to add Unicorn-specific configuration options, that we explain in detail inHeroku's Unicorn documentation:
# config/unicorn.rbworker_processes 3timeout 30preload_app truebefore_fork do |server, worker| Signal.trap 'TERM' do puts 'Unicorn master intercepting TERM and sending myself QUIT instead' Process.kill 'QUIT', Process.pid end defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!endafter_fork do |server, worker| Signal.trap 'TERM' do puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT' end defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connectionendThis default configuration assumes a standard Rails app with Active Record, seeHeroku's Unicorn documentation for more information. You should also get acquainted with the different options inthe official Unicorn documentation.
Now that we've got your app setup to use Unicorn, you’ll need to tell Heroku how to run it in production.
Unicorn in your Procfile
Change the web command in yourProcfile to:
web: bundle exec unicorn -p $PORT -c ./config/unicorn.rbNow try running your server locally with$ foreman start. Once you're happy with your changes, commit to git, deploy to staging, and when you're ready deploy to production.
A World of Concurrency
With the recent release of theRails 4 beta, which is threadsafe by default, it's becoming increasingly clear that Rubyists care about concurrency.
Unicorn gives us the ability to take multiple requests at a time, but it is by no means the only option when it comes to concurrent Rack servers. Another popular alternative isPuma which uses threads instead of forking processes. Puma does however require that your code isthreadsafe.
If you've never run a concurrent server in production, we encourage you to spend some time exploring the ecosystem. After all no one knows your app's requirements better than you.
Whatever you do don't settle for one request at a time. Demand performance, demand concurrency, andtry Unicorn today.
- Originally Published:
- Developer ToolsPerformance OptimizationRailsRuby
Ready to Get Started?
Stay focused on building great data-driven applications and let Heroku tackle the rest.
