Developer Blog

Deploying Rails 4 to Heroku

Heroku is an excellent option for deploying your Rails 4 application and the following setup will allow you to get maximum performance for a minimal cost.

Application Design Choices

Choosing the right services and architecture can go a long way to maximizing performance on Heroku.

Application Server

You have a number of choices for application servers, however you will see your biggest performance gains using clustered Puma. This acts like Unicorn by utilizing several different processes (workers) but still has the mutli-threading provided by Puma. Since your rails app is going to be I/O blocked the vast majority of the time, you will benefit from this setup even on MRI. Add the puma gem to your Gemfile and add the following line to your Procfile:

web: bin/puma -C config/puma.rb -p $PORT

Then in config/puma.rb put:

1
2
3
4
5
6
7
8
9
workers 4
threads 16,16
preload_app!

on_worker_boot do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Base.establish_connection
  end
end

Background Jobs

You should be sending any non-trivial processing to a background job. The best way to maximize the use of your worker dynos is to use sidekiq for your job queue solution. Add the gem to your Gemfile and add the following line to your Procfile:

worker: bin/sidekiq

Optionally you can adjust the number of threads it uses. If most of your jobs are I/O bound try increasing the number of worker threads from the default 25. You can do this with the -c 50 option.

Database

Heroku can support a number of different database options through the Heroku Addons, however the default is Postgres. Postgres has a number of features that give it a great deal of flexibility including support for Hash and Array fields. I highly recommend you use Postgres locally for development as well instead of sqlite. Just add the pg gem to your Gemfile.

Unless you tell Heroku otherwise, you will have a development database which has a number of restrictions. The database has no caching, a limited connection pool, and a limitation on the number of rows you can have in your tables.

Any production application should be using Crane or better which can be added using the web interface or the command line. This will give you a base level of caching, no limitation on the number of rows, and a large 500 connections limit. Depending on your database size and usage you may wish to choose a larger database option which increases your cache.

Amazon S3

If you do any processing of images in your application, I recommend using Carrierwave and storing the images on S3. Furthermore, to reduce any chance of time-outs on uploads, I suggest having your forms upload direct to Amazon S3 and placing a job in Sidekiq to pull the image, process it, and place the processed images back on S3.

Also, rather than having your application serve assets (doesn’t it have something better to do??), look at adding the asset_sync gem to your project. This will allow you to hook into the asset precompile step and ship all of your assets to Amazon S3. Then just set your asset_host to your S3 bucket.

Heroku Rails 4 Support

Heroku treats logs as streams. If you add the following to your Gemfile, your app will handle logging as you expect and will be set to serve assets as well.

gem 'rails_12factor', group: :production

Heroku Ruby 2.0 Support

You should tell Heroku what version of Ruby to use. You can do this in your Gemfile by placing the following line:

ruby '2.0.0'

Heroku Addon Recommendations

Heroku has a large number of very useful Addons, many of which have free options.

PG Backups

Heroku will back up your database but you have to ask them to! Make sure you add on PG Backups. It’s free and you are silly not to. I recommend the “Auto – One Month Retention” option.

Redis (Pick One)

If you added Sidekiq to your application as I have suggested, you need a Redis Addon. There are a number to choose from and some have free tiers which provide plenty of space for your Sidekiq job queue. If you use Redis in other places in your application or expect a large queue depth, then select a larger package as necessary. I’ll leave it up to you to compare price and service.

Memcachier

You can use Redis as your cache store for Rails, but if you use memcache, you can get more cache for your cash using Memcachier, including 25MB in their free tier.

Logs

Heroku logs are not great. That’s probably an understatement. I highly recommend adding in a logging Addon such as Papertrail or Loggly.

Mandrill

Despite the horrible name, if you want to send email from your app, you should look at Mandrill. It is the transactional email service offered by Mailchimp. It works great just as an smtp server but has excellent bonus features like success tracking, open tracking, and you can use your Mailchimp templates.

New Relic

You get the basic version for free, but again you have to tell Heroku you want it. Just add the addon, include the gem in your app and optionally modify the config file. You then get excellent stats of your application performance.

Extra bonus, you can use New Relic’s availability monitoring to keep a single dyno application alive. Just set up availability monitoring and give New Relic and url on your app to ping. I highly suggest creating a specific ping end point that does nothing so it is the lightest load on your application as possible.

Additional Monitoring

I suggest adding some additional monitoring and/or error reporting. Services like Airbrake and Honeybadger both have Heroku Addons that make managing your application errors easy.

Others

There are of course a large number of other Addons which may enhance your application or make your life easier. I suggest browsing through them all and looking for things that will specifically help your particular application.

Wrap Up

So let’s talk about price as that always seems to come up when Heroku is brought up as an option. Let’s first layout what the minimum actually looks like for a true production grade application:

  • Web Dynos (1): Free (See New Relic Tip)
  • Worker Dynos (1): $35
  • Database (Crane): $50
  • PG Backups: Free
  • Redis (Redis Cloud 25MB): Free
  • Memcachier (25MB): Free
  • Papertrail (10MB w/2-Day Search): Free
  • Mandrill (12K Emails/Month): Free
  • New Relic: Free
  • Airbrake (Dev): $9

Total: $94/month

But that’s just the minimum so let’s be realistic and look at what a production application that gets any real amount of traffic actually needs:

  • Web Dynos (2): $35 (1 is Free)
  • Worker Dynos (1): $35
  • Database (Kappa): $100
  • PG Backups: Free
  • Redis (Redis Cloud 25MB): Free
  • Memcachier (250MB): $25
  • Papertrail (100MB w/7-Day Search): $15
  • Mandrill (40K Emails/Month): $5.95
  • New Relic: Free
  • Airbrake (Production): $25

Total: $341.95/month

There are surely cheaper hosting options out there that will give you the same or better performance for less money, however you have to ask yourself as a small start up the following question:

Do I want to spend my time developing my application or maintaining it?

If I don’t spend all the time setting up servers and services, and performing regular maintenance, backups, and worse fixing things when they break, I need to hire someone to do this for me. The best case scenario is you may be able to find an admin to handle all of this on a part-time basis, but even at part time you are probably spending at least $500/month.

So, find out what cheaper hosting solution you would like to use, factor in any of the services provided by Addons that you are not going to set up yourself on this platform. Whatever that total is, take the delta from your Heroku bill. If this difference is less than you can hire someone to do the work for you, then you can start considering options other than Heroku. Until then, reduce your stress and just git push heroku.

Comments