rails unicorn - herokaijp/devcenter GitHub Wiki
ããã»ã¹ã䞊åã«ãªã¯ãšã¹ããæãããããªãŠã§ãã¢ããªã±ãŒã·ã§ã³ã¯ãåãæéã«äžã€ã ããããªã¯ãšã¹ããæããªãã¢ããªã±ãŒã·ã§ã³ã«æ¯ã¹ãŠãDynoã®ãªãœãŒã¹ãããå¹ççã«äœ¿ããç¶æ ã«ãªããŸããåŸã£ãŠã䞊åãªã¯ãšã¹ãåŠçã¯æ¬æ ŒçãªãµãŒãã¹ãéçºãéçšãããããªãå Žåã§ãæšå¥šãããŸãã
Railsã¯å ã ã¯åæã«ïŒãªã¯ãšã¹ãããåŠçããªãããã«èšèšããããŠããŸãããããŠãåŸã ã«ãã®èšèšãããåäœã®Rubyããã»ã¹å ã§ãªã¯ãšã¹ãã®äžŠååŠçãèš±ããããªã¹ã¬ããã»ãŒãã®å®è£ ãžãšç§»è¡ããŠããŸããããã仿¥ã§ã¯ãã»ãšãã©ã®Rubyã¢ããªã±ãŒã·ã§ã³ã¯ãµããŒããããŠããŸããã
UnicornãŠã§ããµãŒãã¯ãäžã€ã®Dynoã§è€æ°ã®Rubyããã»ã¹ãèµ°ãããäºã§ãã©ããªRailsã¢ããªã±ãŒã·ã§ã³ã§ã䞊åã«èµ°ãããããããã«ãªããŸãã
ãã®ã¬ã€ãã§ã¯ãUnicornãŠã§ããµãŒãã䜿ã£ãHerokuãžã®Railsã¢ããªã±ãŒã·ã§ã³ã®ãããã€ãèŠãŠè¡ããŸããåºæ¬çãªRailsã®ã»ããã¢ããã¯Getting Started with Railsãã芧ãã ããã
補åãšããŠããªãã®ã¢ããªããããã€ããåã«ããã€ãã¹ããŒãžã³ã°ç°å¢ã§æ°ãããããã€ãããç©ããã¹ãããŠãã ããã
Unicornã¯å ¥åããããªã¯ãšã¹ããåæã«å¶åŸ¡ããããã«åå²ãããããã»ã¹ã䜿ãRack HTTP ãµãŒãã§ãã
å§ãã«ããŠãã³ãŒã³ãããªãã®ã¢ããªã®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ã®ããã¥ã¡ã³ããã芧ãã ããã
:::ruby
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
Unicornã¯ãRailsã¢ããªãã¹ã¬ããã»ãŒãã§ãããã©ãããèããã«ãè€æ°ã®äžŠåãªã¯ãšã¹ãããµããŒãããããšãåºæ¥ãããã«ãããããã®Dynoã®äžã§è€æ°ã®OSããã»ã¹ãžåå²ãããŸããUnicornã®å°éçšèªã§ãããã¯ã¯ãŒã«ãŒããã»ã¹ãšããŠèšåãããŸãã®ã§ãDynoã®äžã§èµ°ã£ãŠããHerokuã®ã¯ãŒã«ãŒããã»ã¹ãšæ··åããªãããã«ããŠãã ããã
ããããã®åå²ãããOSããã»ã¹ã¯æŽãªãã¡ã¢ãªãæ¶è²»ããŸããããã¯ããªããäžã€ã®Dynoã§ã©ãã ãã®ããã»ã¹ãå®è¡ã§ããããå¶éããŸããå
žåçãªRailsã®ã¡ã¢ãªäœ¿çšéãããããšã2~4ã€ã®Unicornã®ã¯ãŒã«ãŒããã»ã¹ãå®è¡ã§ãããšäºæ³ãããŸããããªãã®ã¢ããªã±ãŒã·ã§ã³ã¯å€ããå°ãªãããå
·äœçãªã¡ã¢ãªäœ¿çšéã«ãã£ãŠåŠçãèš±å¯ããã§ãããããããŠç§ãã¡ã¯ã¢ããªã±ãŒã·ã§ã³ã®èª¿æŽãæ©ãããããã«ããã®æ°åãèš±å¯ããããã®èšå®å€æ°ãšããŠæç€ºããŠããããšãããããããŸããheroku logs
ããã°ã®ã¢ããªã³ã®ã©ããã䜿ã£ãŠR14ãšã©ãŒ(ã¡ã¢ãªå²åœè¶
é)ãããªãã®ã¢ããªã®ãã°ããç£èŠããŠãã ããã
:::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ãããªãã®ã¢ããªã«ãã£ãŠãªã¯ãšã¹ããåŠçããå§ãããšãã«ã«ãŠã³ãããŠã³ãå§ãŸããã¬ã¹ãã³ã¹ãåž°ããšãã«çµãããŸãããããªã¯ãšã¹ããæ±ºãŸã£ãæéãããé·ãæéãåã£ãŠããå Žåããã¹ã¿ãŒã¯ãªã¯ãšã¹ããæã€ã¯ãŒã«ãŒã«SIGKILLããŸãã
:::ruby
timeout 15
ç§ãã¡ã¯15ç§ã®ã¿ã€ã äŒããšãæšå¥šããŸããïŒïŒç§ã®ã¿ã€ã ã¢ãŠããèšå®ããŠãããšããã¹ã¿ãŒããã»ã¹ã¯ãªã¯ãšã¹ãã®åŠçã«15ç§ä»¥äžæéãããã£ãŠããã¯ãŒã«ã«å¯ŸããŠSIGKILL
ãéããŸãããã®å Žåã¯H13ãšã©ãŒãçæãããã°ã®äžã§ç¢ºèªããããšãã§ããŸããæ³šæãã¹ãç¹ãšããŠãããã¯ãããã°ãæ¯æŽããããã®ã¹ã¿ãã¯ãã¬ãŒã¹ã¯çæããŸããã
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ã®ã¿ã€ã ã¢ãŠãã®å€ãããäœãããã¹ãã§ãã
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
ããã»ã¹ã¿ã€ãã«å¥ã®ã³ãã³ããå®çŸ©ããŠãã ããã