unicornでgraceful restartする

unicornを無停止で再起動(新しい設定をリロード) すなわちgraceful restartさせるのにはマスタープロセスに対して kill -s USR2 すると薄ら理解していたのですが、そのためにはきちんと設定がいるのでその際の対応と、実際に行った際に観察したプロセスをメモしておきます。

まず、設定しているunicorn.confには以下の設定を記載しておきます。

よく参照されているunicorn.conf.rb の中でコメントアウトされている辺りを有効にする必要があります。

また、リスタート時にGemfileのパスを強制的に指定させる様にしているのは、graceful restartさせた後に新しいGemfileの更新を適用させるためです。

before_fork do |server, worker|
  ENV['BUNDLE_GEMFILE'] = "#{pj_root_dir}/current/Gemfile"

  # The following is only recommended for memory/DB-constrained
  # installations.  It is not needed if your system can house
  # twice as many worker_processes as you have configured.
  #
  # # This allows a new master process to incrementally
  # # phase out the old master process with SIGTTOU to avoid a
  # # thundering herd (especially in the "preload_app false" case)
  # # when doing a transparent upgrade.  The last worker spawned
  # # will then kill off the old master process with a SIGQUIT.
  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

上の記述がある状態でunicornを起動していれば、USR2シグナルをmasterのプロセスに送るとgraceful restartできます。

試しに手動でプロセスをkillしてみます。まずは現状を確認。masterのプロセスは7864であることが確認できます。

remper    7864 66.2  7.1 320460 72732 ?        Sl   23:11   0:05 unicorn master -c config/unicorn.conf -E production -D
remper    7876  0.0  6.7 320460 69156 ?        Sl   23:11   0:00 unicorn worker[0] -c config/unicorn.conf -E production -D
remper    7880  0.0  6.7 320460 69148 ?        Sl   23:11   0:00 unicorn worker[1] -c config/unicorn.conf -E production -D

この状態から、master processをkillしてみます。

$ kill -s USR2 (unicorn master processのPID, ここでは7864)

とすると、現行のmasterが新しいmasterをforkします。 (下のプロセス一覧だと7908というPIDが該当)

remper    7864 15.2  7.1 320460 72900 ?        Sl   23:11   0:05 unicorn master (old) -c config/unicorn.conf -E production -D
remper    7876  0.0  6.8 321488 69744 ?        Sl   23:11   0:00 unicorn worker[0] -c config/unicorn.conf -E production -D
remper    7880  1.2  7.0 320896 71576 ?        Sl   23:11   0:00 unicorn worker[1] -c config/unicorn.conf -E production -D
remper    7908 57.0  2.2  84032 23164 ?        Rl   23:11   0:00 ruby /〜/releases/11/vendor/bundle/ruby/1.9.1/bin/unicorn -c config/unicorn.conf -E production -D

そして、いままでのmasterから生えていたworkerが無くなって、新しいworkerが新しいmasterから生えてきます。

下の一覧だと unicorn worker[(0|1)] というプロセスのPIDが上のPID一覧のものと換わっているのがわかります。

remper    7908 44.6  7.1 320580 72736 ?        Sl   23:11   0:05 unicorn master -c config/unicorn.conf -E production -D
remper    7922  0.0  6.7 320580 69116 ?        Sl   23:11   0:00 unicorn worker[0] -c config/unicorn.conf -E production -D
remper    7926  0.1  6.7 320580 69112 ?        Sl   23:11   0:00 unicorn worker[1] -c config/unicorn.conf -E production -D

ということで、unicorn.confに適切な設定を記載することでgraceful restartさせることができました。

そして、もろもろこの辺り調べていると大抵私が所属しているペパボのエンジニアの方のブログにぶつかって便利。そして感謝。

参照

Unicornのgraceful restartで少しハマった件 - blog.tnmt.info