こんにちは、tahara です。
いこーよ では Passenger を使っていました。 最近チケット毎に Docker でステージングを作り、リリースする流れになった中、 デプロイ時の再起動でリクエストがつまってしまうのが問題になってきました。 そのため Unicorn に変えました。
実は以前 Uricorn を使っていました(さらにその前は Passenger です)。 そのころはさくらの専用サーバでした。
さくらから AWS にのりかえた際に Passenger にしました。 AWS のオートスケールでのデプロイ対応のためです。
いこーよは NFS サーバを動かしており、全 Rails サーバは NFS マウントして最新のコードを共有しています。 そうすれば、いつオートスケールしても問題なく最新のコードを参照でき、デプロイ毎に AMI を使り直す必要もありません。 オートスケールでの Rails サーバのたちあがりも、起動時にコードを最新にする必要がないので高速です。
オートスケールで Rails サーバが起動、停止するなか、 どの Rails サーバがいま動いているかを気にすることなく、デプロイは NFS サーバに対してだけおこないます。
Passenger なら全 Rails サーバの再起動は NFS サーバで touch tmp/restart.txt するだけです。
しかし Unicorn では USR2 シグナルを各 Rails サーバでなげる必要があります。
というわけでちょっとハックしました。
unicorn.conf.rb
before_fork do |server, worker| # the following is highly recomended for Rails + "preload_app true" # as there's no need for the master process to hold a connection defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! # oldsig QUIT 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 end end # watch restart.txt if worker.nr == 0 listener = Listen.to('/app/current/tmp/unicorn_restart', force_polling: true ) do |modified, added, removed| pid = server.config[:pid] if pid == server.pid begin Process.kill("USR2", File.read(pid).to_i) rescue Errno::ENOENT, Errno::ESRCH end end end listener.start end end
上記のコードでは /app を NFS マウントしています。 デプロイ時にNFS サーバで touch /app/current/tmp/unicorn_restart/restart.txt します。 そうすると Unicorn 自身がファイル変更を検知し、自分自身に USR2 シグナルをなげます。 まるで Passenger みたい。
NFS の場合は inotify が使えません。そのため incron の使用もあきらめ、上記の Listen でも force_polling: true としています。
また NFS のマウントオプションに actimeo=3 を付けキャッシュの有効期間を 3 秒にしました。 デフォルトでは 60 秒なので、Unicorn の再起動までかなり待つはめになります。 ちなみに actimeo=0 にしたら Unicorn が起動しなくなってしまいましたorz
Passenger と同じく touch /app/curret/tmp/restart.txt にしたかったのですが、 /app/curret/tmp 以下にあるファイル数が多いとファイル監視で CPU リソースをかなり使ってしまいます。 そのため専用のディレクトリ /app/current/tmp/unicorn_restart を用意しました。
問題点は NFS サーバが単一障害点である、ことですね...
ちにみに、いこーよでは Passenger と Unicorn でほとんどパフォーマンスに差はありませんでした。