Unicorn+Rails入門
Railsでよく使われているサーバーUnicornについて勉強しておこうと思います。以前Unicorn+Nginxで動かそうとしたらうまく動かせなかったので、とりあえずゼロからテストアプリ作って、Unicornで動かすまでを1つづつ勉強して仕組みを理解して行こうと思います。
rails new unicorn_sample
cd unicorn_sample
rails g scaffold article title:string content:string
rake db:migrate
vim config/routes.rb
routes.rb
+ root "articles#index"
で動くアプリを一応作成
Unicornを導入
Gemfile
+ gem 'unicorn'
bundle install
touch config/unicorn.rb
https://github.com/herokaijp/devcenter/wiki/Rails-unicorn を参考に
config/unicorn.rb
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3) # 子プロセスいくつ立ち上げるか timeout 15 #15秒Railsが反応しなければWorkerをkillしてタイムアウト preload_app true #後述 # 同一マシンでNginxとプロキシ組むならsocketのが高速ぽい(後述ベンチ) # listen /path/to/rails/tmp/unicorn.sock listen 3000 # pid file path Capistranoとか使う時は要設定か # pid /path/to/rails/tmp/pids/unicorn.pid # ログの設定方法. #stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) #stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) before_fork do |server, worker| old_pid = "#{ server.config[:pid] }.oldbin" if File.exists?(old_pid) && server.pid != old_pid begin # 古いマスターがいたら死んでもらう Process.kill("QUIT", File.read(old_pid).to_i) rescue Errno::ENOENT, Errno::ESRCH # someone else did our job for us end 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 def rails_root require "pathname" Pathname.new(__FILE__) + "../../" end
namespace :unicorn do ## # Tasks desc "Start unicorn" task(:start) { config = rails_root + "config/unicorn.rb" env = ENV['RAILS_ENV'] || "development" sh "bundle exec unicorn_rails -D -c #{config} -E #{env}" } desc "Stop unicorn" task(:stop) { unicorn_signal :QUIT } desc "Restart unicorn with USR2" task(:restart) { unicorn_signal :USR2 } desc "Increment number of worker processes" task(:increment) { unicorn_signal :TTIN } desc "Decrement number of worker processes" task(:decrement) { unicorn_signal :TTOU } desc "Unicorn pstree (depends on pstree command)" task(:pstree) do sh "pstree '#{unicorn_pid}'" end ## # Helpers def unicorn_signal signal Process.kill signal, unicorn_pid end def unicorn_pid begin File.read(rails_root + "tmp/pids/unicorn.pid").to_i rescue Errno::ENOENT raise "Unicorn doesn't seem to be running" end end def rails_root require "pathname" Pathname.new(__FILE__) + "../" end end
rake unicorn:start
再起動
rake unicorn:restart
終了
rake unicorn:stop
preload_appの挙動についてのまとめ.良い記事があったのでそのまま引っ張らせて頂きます。 unicornのpreload_app
preload_appの設定によって、SIGHUP(workerの処理の完了をもって再起動)を送ったときに挙動が違ってくる。
true
unicornの設定:再読み込みされる アプリのリロード:されない。アプリはマスタでロード済みのものを使う。アプリをリロードしたければ、SIGUSR2を送って新マスタ&workerを立ち上げる方法をとる。 ダウンタイム:発生しない(マスタのアプリをそのまま使うので、workerがあがった時から処理が可能)
false
unicornの設定:再読み込みされる アプリのリロード:される ダウンタイム:発生する。(workerがそれぞれアプリをロードするので、ロード完了まで処理できない)
ダウンタイム無しでデプロイが可能という特徴に繋がっているようです。
参考
設定を参考にしてみた
http://qiita.com/corona6@github/items/cfac19432532d261912d
https://gist.github.com/honjo2/5023446
https://github.com/herokaijp/devcenter/wiki/Rails-unicorn
githubチームのunicornの事例(tcpとsocketベンチとってる記事)
https://github.com/blog/517-unicorn
Unicorn自体についての日本語の詳細な解説 http://w.koshigoe.jp/study/?ruby-unicorn-intro
デプロイ時の処理に付いていろいろ https://gist.github.com/falcon8823/3804095