FIVETEESIXONE

Heroku で動かしているアプリケーションの Web サーバーを Unicorn から Puma に変更する


Heroku の推奨する Ruby Web サーバーが Puma に変更になったとのアナウンスがありました。

Puma is Now the Recommended Ruby Webserver

もともと、何となく「1 Dyno で動かすなら Unicorn より Puma の方がいいんじゃないのかな?」とか思って Puma を好んでいました (ただ、ぶっちゃけロクに調べておらず、この考えはたぶん間違ってたと思う)。

が、Rails アプリが 1 つあって、その Web サーバーが Unicorn だったのでこの機会に変えました。

一応ここにその手順を書いておきますが、Deploying Rails Applications with the Puma Web Server を読んだ方がずっと良いでしょう…

Migrate from Unicorn to Puma

Heroku の推奨する構成にしたがって変更するだけならあっという間です。

Gemfile に Puma を追加する

Gemfile に Puma を追加します。同時に、不要になる Unicorn は削除しておきます。

Gemfile

# Use Puma as the app server
gem 'puma'
$ bundle install

config/puma.rb を作る

Puma の起動設定ファイルを作成します。以下の構成が Heroku がオススメする標準構成です。

config/puma.rb

workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end

ちょっとだけ中身に触れておききましょう。Puma には、WorkerThread という、並行処理のための 2 つの単位があります。

Worker

  • Puma が複数リクエストを同時に捌くために起動するプロセスのこと
  • workers Integer(ENV['WEB_CONCURRENCY'] || 2) のところ

Thread

  • 起動した各 Worker の中で更に起動するスレッドのこと
  • MRI では GIL (GVL) があるため IO 処理や外部への http リクエストなどでのみ有効。
  • threads_count = Integer(ENV['MAX_THREADS'] || 5) のところ。

もしアプリケーションがスレッドセーフではない作りになっているのであれば、以下のようにして最大起動 Thread 数を 1 つに制限する必要があります。

$ heroku config:set MAX_THREADS=1

Procfile を変更する

上記で作った構成ファイルを読み込んで Puma が起動するように Procfile を変更します。

Procfile

web: bundle exec puma -C config/puma.rb

config/unicorn.rb を削除

不要になった config/unicorn.rb を削除します。

$ git rm config/unicorn.rb

Puma の起動テスト

問題なく起動するかどうか確認します。

$ env RACK_ENV=production bundle exec puma -C config/puma.rb

Heroku へのデプロイ

バッチリ起動することが確認できたら、いつものように Heroku にデプロイして完了です。

$ git add -A
$ git commit -m"Migrate web server from Unicorn to Puma"
$ git push heroku master