トップ «前の日記(2009-11-07) 最新 次の日記(2009-11-12)» 編集

Route 477



2009-11-10

[ruby] 大規模Railsサイトのための新しいHTTPサーバ、Unicorn

githubの中の人が、ブログで「Unicorn使い始めて一ヶ月くらい経つけどいい感じだよ」と書いています。 適当に要点だけ拾ってみました。

Unicornって何よ?

UnicornはRubyのためのHTTPサーバ。MongrelやThinのようなものだけど、全く違う設計と思想を持っている

ありがちな構成

                         [mongrel] [mongrel] ..
 [nginx] -> [haproxy] -> [mongrel] [mongrel] ..
                         [mongrel] [mongrel] ..

問題点:

  1. あるactionの処理に60秒以上かかったとき、Mongrelが当該スレッドをkillしようとして固まることがある
  2. メモリが一定量を超えたときMongrelを再起動するのが遅い。
  3. デプロイ時に9個のmongrelが同時に再起動するので重い(対策もややこしい)
  4. mongrel1つの再起動もけっこう遅い
  5. push方式のバランシングなので、本当にうまいインスタンスが選ばれるか分からない

そこでUnicornですよ

             Unix       [unicorn worker] [unicorn worker] ..
 [nginx] -> ドメイン -> [unicorn worker] [unicorn worker] ..
            ソケット    [unicorn worker] [unicorn worker] ..

nginxを、Unixドメインソケット*1経由でUnicorn workerにリクエストを送るように設定

  • Unicorn masterは起動すると、まずアプリケーションをロードする。ロードが終わり次第、16個のworkerをforkする (つまり、workerが16個でもロードは1回だけ)
  • 各workerはselect()でソケットからの入力を待つ (つまり、workerが暇になったらリクエストを処理する。いわばカーネルによるロードバランシング)

問題点がどう変化するか:

  1. workerの処理が30秒*2以上かかると、masterはこのworkerをkillして新しいのをforkする。(forkなので、インスタンスの生成は一瞬で終わる)
  2. workerがメモリを食いすぎると、godやmonitからSIGQUITが送られる。すると、workerは「リクエストが終わり次第」exitする。(リクエストの途中でkillされることがない)
  3. デプロイ時は、Unicorn masterにSIGUSR2を送る。
    • するとmasterは新しいmasterを起動し、新しいアプリケーションコードが読み込まれ、workerがforkされる。
    • 最初のworkerが古いmasterの存在を検知し、SIGQUITを送る。古いmasterは自分のworkerたちを終了してexitする。
    • 常にいずれかのworkerが動いているので、ダウンタイムがない。また、新旧のworkerは同じソケットを使うので、nginxは変化に気づかない。
  4. Unicornの再起動は速い(masterが1回コードをロードするだけなので)。workerの再起動もkillしてforkするだけなのでとても速い。
  5. pull方式なので、バランシングはworkerが暇になったら自分で取りに行くだけと単純そのもの。

本文ではこのあと移行のためのヒントと、githubで使われている設定、ベンチマークが紹介されています。

関連しそうな書籍

4873114004

4873114160

おまけ

姉妹品のRainbows!も気になってるんだけど、いまいちよく分かんないです (workerの粒度と並列化方法を切り替えられるようにすることで、long-pollとかに対応する??)

*1 TCPにすることもできる

*2 設定可能

本日のツッコミ(全1件) [ツッコミを入れる]
okkez (2009-11-10 23:21)

Rainbows! は低スペックなマシン用のやつらしいです。