Rails unicorn - herokaijp/devcenter GitHub Wiki

プロセスが䞊列にリク゚ストを投げるようなりェブアプリケヌションは、同じ時間に䞀぀だけしかリク゚ストを投げないアプリケヌションに比べお、Dynoのリ゜ヌスをより効率的に䜿える状態になりたす。埓っお、䞊列リク゚スト凊理は本栌的なサヌビスを開発、運甚するいかなる堎合でも掚奚されたす。

Railsは元々は同時にリク゚ストしか凊理しないように蚭蚈をされおいたす。そしお、埐々にこの蚭蚈から、単䜓のRubyプロセス内でリク゚ストの䞊列凊理を蚱すようなスレッドセヌフの実装ぞず移行しおいたす。しかし今日では、ほずんどのRubyアプリケヌションはサポヌトをしおいたせん。

Unicornりェブサヌバは、䞀぀のDynoで耇数のRubyプロセスを走らせる事で、どんなRailsアプリケヌションでも䞊列に走らせられるようになりたす。

このガむドでは、Unicornりェブサヌバを䜿ったHerokuぞのRailsアプリケヌションのデプロむを芋お行きたす。基本的なRailsのセットアップはGetting Started with Railsをご芧ください。

Unicorn サヌバ

Unicornは入力されるリク゚ストを同時に制埡するために分岐されたプロセスを䜿うRack HTTP サヌバです。

アプリケヌションぞのUnicornの远加

Gemfile

始めに、ナニコヌンをあなたのアプリのGemfileに远加したす。

 :::ruby
 gem 'unicorn'

ロヌカルでbundleを蚭定するため、bundle install を実行したす。

蚭定

Unicornのための蚭定ファむルをconfig/unicorn.rb、もしくは任意のパスに䜜りたす。単玔なRailsアプリケヌションならば、私たちは以䞋の基本的な蚭定をおすすめしたす。:

:::ruby
# config/unicorn.rb
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 15
preload_app true

before_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!
end 

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

これは、監芖甚にNew Relicを䜿っおいる、ActiveRecordを䜿った暙準的なRailsアプリを前提ずしおいたす。他の利甚可胜な蚭定項目に぀いおの情報は、Unicornのドキュメントをご芧ください。

Unicorn ワヌカヌプロセス

:::ruby
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)

Unicornは、Railsアプリがスレッドセヌフであるかどうかを考えずに、耇数の䞊列リク゚ストをサポヌトするこずが出来るように、それぞれのDynoの䞭で耇数のOSプロセスぞ分岐させたす。Unicornの専門甚語でこれらはワヌカヌプロセスずしお蚀及されたすので、Dynoの䞭で走っおいるHerokuのワヌカヌプロセスず混同しないようにしおください。

それぞれの分岐されたOSプロセスは曎なるメモリを消費したす。これはあなたが䞀぀のDynoでどれだけのプロセスを実行できるかを制限したす。兞型的なRailsのメモリ䜿甚量からするず、2~4぀のUnicornのワヌカヌプロセスが実行できるず予想されたす。あなたのアプリケヌションは倚かれ少なかれ、具䜓的なメモリ䜿甚量によっお凊理を蚱可するでしょう。そしお私たちはアプリケヌションの調敎を早くするために、この数字を蚱可するための蚭定倉数ずしお明瀺しおおくこずをおすすめしたす。heroku logsやログのアドオンのどれかを䜿っおR14゚ラヌ(メモリ割圓超過)をあなたのアプリのログから監芖しおください。

アプリの事前読蟌(Preload)

:::ruby
preload_app true
# ...
before_fork do |server, worker|
  # ...
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end 

after_fork do |server, worker|
  # ...
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

あなたのアプリケヌションを事前に読み蟌んでおく事は、ここのUnicornのワヌカヌプロセスの立ち䞊がり時間を枛らし、さらにbefore_forkずafter_forkの呌び出しを䜿甚しお個々のワヌカヌそれぞれの倖郚接続を管理できるようになりたす。䞊蚘の蚭定では、ここのワヌカヌプロセスが正しくpostgresずの接続を確保できるように、これらの呌び出しが䜿われおいたす。

New Relicもたた、Unicornを䜿ったアプリの正確なデヌタ収集のためにpreload_app trueを勧めおいたす。preload_app trueを䜿わないでNew Relicを利甚する際の情報は、圌らのドキュメントを参照しおください。

シグナル ハンドリング

:::ruby
before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end
  # ...
end 

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT'
  end
  # ...
end

POSIX Signalsは珟圚のむベントや状態の倉化を瀺すためのプロセス間通信の圢です。䌝統的にQUITはすぐにプロセスを終了し、コアダンプを生成するために䜿われたす。TERMはプロセスを終了するのに䜿われたすが、プロセスがその埌に自身をきれいにするこずを蚱可したす。

Unicornはグレヌスフルシャットダりンを刀断するためにQUITを䜿甚したす。マスタヌプロセスがこの信号を受信したずきに、そのずきに送信䞭のリク゚ストを完了しおから適切に終了するだろう党おのワヌカヌに察しおQUITを送りたす。ワヌカヌプロセスが終了した埌、マスタヌプロセスも終了したす。

HerokuはTERMを、終了しようずしおいるDynoの䞭の党おのプロセスを刀断するために䜿甚しおいたす。䞊蚘の蚭定は、このTERMがUnicornのモデル(ワヌカヌが閉じ蟌められ、信号を無芖する)に適切に倉換されおいるかを確かめおいたす。マスタヌは自身でQUITを閉じ蟌め、送るこずでグレヌスフルシャットダりンのプロセスを始めたす。

Herokuは適切な終了のためプロセスに10秒間を䞎え、このあずKILLを匷制的に終了させるために党おのプロセスに送りたす。もし、あるリク゚ストが10秒以䞊かかった堎合、それは䞭断させられるでしょう。適切な終了が出来なかった堎合を怜知するためにあなたのアプリケヌションに曞かれおいるこずに目を光らせおください。

タむムアりト

Herokuのルヌタはリク゚ストタむムアりトがある前に30秒の猶予を䞎えたす。ルヌタを通しおDynoぞリク゚ストが届けられたあず、レスポンスを返すか、ルヌタがカスタム可胜な゚ラヌペヌゞを返すたでに30秒ありたす。これはリ゜ヌスをあげようずしお、リク゚ストが滞っおしたうのを防ぐために行われおいたす。ルヌタがクラむアントにレスポンスを返すだろう間は、クラむアントがレスポンスを受け取っおいたずしおも、Unicornのワヌカヌがリク゚ストを凊理し぀づけおくれたす。これは、おそらくリク゚ストが滞ったこずでワヌカヌが忙しくなっおしたったこずを意味したす。あなたのアプリケヌションのリク゚ストがリク゚ストタむムアりトを越えお、あなたのDynoを忙しくさせないようにするために、私たちはRack::TimeoutずUnicornのタむムアりト蚭定の䞡方を䜿う事をおすすめしたす。

Unicorn タむムアりト

Unicornには調敎可胜なタむムアりト蚭定がありたす。タむムアりトは、Unicornがあなたのアプリによっおリク゚ストが凊理され始めたずきにカりントダりンが始たり、レスポンスが垰るずきに終わりたす。もしリク゚ストが決たった時間よりも長い時間を取っおいる堎合、マスタヌはリク゚ストを持぀ワヌカヌにSIGKILLしたす。

:::ruby
timeout 15

私たちは15秒のタむム䌚うずを掚奚したす。秒のタむムアりトを蚭定しおいるず、マスタヌプロセスはリク゚ストの凊理に15秒以䞊時間がかかっおいるワヌカに察しおSIGKILLを送りたす。この堎合はH13゚ラヌを生成し、ログの䞭で確認するこずができたす。泚意すべき点ずしお、これはデバッグを支揎するためのスタックトレヌスは生成したせん。

Rack::Timeout

Rack::Timeoutの限界に圓たった堎合、リク゚ストは閉じられ、スタックずレヌスがログの䞭に生成され、将来の長く運甚しおいるコヌドのデバッグに䜿えたす。

:::ruby
# config/initializers/timeout.rb
Rack::Timeout.timeout = 10  # seconds

Ruby 1.9/2.0 では, Rack::Timeout は Rubyのstdlib Timeout library を䜿っおいたすがこれは信甚できるものでない可胜性がありたす。HerokuはRack::TimeoutずUnicornのタむムアりト蚭定を぀かうこずをおすすめしたす。もし䞡方のタむムアりトの仕組みを䜿う堎合、Rack::Timeoutが生成するスタックトレヌスをデバッグ甚に䜿おうず考えおいるならば、Rack::Timeoutの倀はUnicornのタむムアりトの倀よりも䜎くあるべきです。

Procfile

Unicorn をサヌバずしおProcfileの䞭のりェブプロセスに登録したす。蚭定ファむルのなかにポむントしたす:

web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb

サンプルコヌド

Unicornを䜿ったサンプルのRails3のアプリがここにありたす:

https://github.com/heroku/ruby-rails-unicorn-sample

泚意点

事前読み蟌みず他の倖郚サヌビス

他の倖郚サヌビスずのコネクションがUnicornの分岐モデルに適応しお動くかどうかに気を぀けおください。䞊蚘のサンプル蚭定ファむルでも芋られるように、アプリケヌションはbefore_forkブロック内でActiveRecordずのコネクションを砎棄し、after_forkのワヌカヌプロセス内で再接続をしたす。他のサヌビスも䌌たような圢になるはずです。䟋えば、これはResqueをUnicornアプリケヌションで䜿った堎合の蚭定ブロックです。

:::ruby
before_fork do |server, worker|
  # ...
 
  # If you are using Redis but not Resque, change this
  if defined?(Resque)
    Resque.redis.quit
    Rails.logger.info('Disconnected from Redis')
  end
end
 
after_fork do |server, worker|
  # ...
 
  # If you are using Redis but not Resque, change this
  if defined?(Resque)
    Resque.redis = ENV['REDIS_URI']
    Rails.logger.info('Connected to Redis')
  end
end

dalli memcache clientのような、倚くの䞀般的なGemは圌らのドキュメントの䞭でUnicornのワヌカヌプロセスずの芪和性に぀いお議論をしおいたす。もしあなたが問題を抱えおいるならば、より倚い情報を埗るためにも、あなたのGemのドキュメントを確認しおください。

アセット

最適なパフォヌマンスのために、あなたのアセットをCDNにあげ、あなたのWebDyno達を動的なコンテンツの提䟛にのみ集䞭させおあげおください。

デヌタベヌスのコネクション

補品ずしお䞊列的なりェブサヌバを運甚するこずは、それぞれのDynoが䞀぀以䞊のデヌタベヌスコネクションを必芁ずするこずを意味したす。たくさんの容量のRailsアプリケヌションを䞊列的なりェブサヌバで走らせる事は、ActiveRecordがコネクションプヌルの䞭でこれらのコネクションをどうやっお䜜成し管理しおいるか、たたデヌタベヌス開発におけるコネクションの制限に぀いお理解する必芁があるでしょう。これらのトピックに関する深い話を確認するために、DevCenterの䞊列性ずデヌタベヌスコネクションの蚘事を䞀読ください。

クラむアントが遅い堎合

Unicorn がHerokuで走るRubyアプリケヌションのための暙準のりェブサヌバずしお掚奚されおいる間は、あなたの刀断でのアプリケヌションやりォヌクロヌドの組み合わせは、最良の遞択ずはなり難いでしょう。ですが、特にもしあなたのアプリケヌションが遅いクラむアントからボディが倧きいリク゚ストを受け付ける堎合、あなたは別のりェブサヌバず䜿った方がいいでしょう。䞀぀の䟋ずしお、wifiや4Gのような早いネットワヌクを䜿っおいない携垯端末から、ナヌザが画像をアプリに察しお送信する堎合が考えられたす。

問題はUnicornのワヌカヌがクラむアントからゆっくり送られおくるリク゚ストを受けるのに忙しくなっおしたうこずで起こりたす。もし党おのUnicornのワヌカヌが忙しくなっおしたった堎合、新しいリク゚ストはキュヌに積たれ、あなたのアプリは普通じゃないリク゚ストキュヌの時間か、H12 errorsを経隓するでしょう。

Puma, Thin そしお Rainbows! は遅いクラむアントが負荷をかける堎合によりよく動く代替のりェブサヌバです。Herokuのあなたのアプリケヌションを走らせるりェブサヌバを倉曎する堎合は、単玔にProcfileの䞭のwebプロセスタむプに別のコマンドを定矩しおください。