ぱろっと・すたじお

技術メモなどをまったりと / my site : http://parrot-studio.com/

Rails3アプリをnginx+unicornで動かしたら速すぎた

いやぁ・・・Rails3はいいですね(`・ω・´) b


Rails2とはなんだったのか・・・というレベルの完成度で、
なんとなく納得しないままRails2を使っていた私も、
Rails3になってからはバリバリに使いまくりです*1


そんなRailsを動かすAppサーバとして、
以前から定番になっていたのがpassengerでして、
私もApacheやnginxと組み合わせて使ってました*2


ただ、最近よく耳にするのがnginxにunicornを組み合わせた構成です


http://unicorn.bogomips.org/


前々から気になっていたものの、なかなか手をつけられなかったのですが、
仕事でもプライベートでもちょうどRails3アプリをリリースするタイミングだったので、
nginx+unicornの環境を試してみました


なお、非常に細かな解説がある良記事がありますので、
ぜひそちらを先に(´・ω・)っ


次世代RailsサーバーUnicornを使ってみた « BPS株式会社 開発ブログ Beyond Perspective Solutions LTD.

環境

  • /path/to/app にアプリの実体があるとする
  • nginxは /usr/local/nginx にインストール
  • サーバ名はhogehoge.piyo
  • unicornのポートは8080

nginxのインストール


ソースからmakeしてもいいのですが、
今回はpassenger経由で入れてみました
後々passengerに切り替える場合でも楽ですし・・・


途中、デフォルトインストールか細かいconfigureを使うか聞かれますが、
デフォルトでもprefixの指定はできるので問題ないかと


このやり方だと、nginx.confにpassenger絡みの記述が追加されますが、
コメントアウトすればOKです

unicornのインストールと起動


gemなのでインストールは簡単です


「gem install unicorn」でもいいのですが、
Gemfileに「gem 'unicorn'」を追加して「bundle install」の方が、
Rails3としては正しいかと

$ cd /path/to/app
$ vi Gemfile # 「gem 'unicorn'」を追加
$ bundle install
$ unicorn_rails # -D でデーモン化 -E でRAILS_ENV指定 -c でconfig

・・・と、これで起動してくれればいいのですが、
rackに関するエラーが出る場合がありますΣ(゚Д゚)ガーン


この場合、bundleを経由して実行する必要があります
rspecの単体起動と同じ)

$ bundle exec unicorn_rails 

本番サーバで起動する場合も同じ手段がいるかもしれません


これで起動が確認できたら、RAILS_ROOT/config/unicorn.rb あたりに、
unicornの設定を書いておきます


さっきのサイトだとあまりに細かすぎるので、
このあたりを参考に(´・ω・)っ


http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
http://d.hatena.ne.jp/milk1000cc/20100804/1280893810


私はminimalをベースに、before_fork / after_forkを付け加える感じにしました


あとはconfig指定で動かして確認してみましょう

$ cd /path/to/app
$ bundle exec unicorn_rails -E production -c config/unicorn.rb

オプションに-DをつけなければCTRL+Cで止められます


initスクリプトは以下を参考にしました
基本的にアプリ単位でのスクリプトになります


https://gist.github.com/308216


念のためunicorn_railsをbundle exec経由に変更しました

nginx+unicorn連携


実はunicornはあまり関係なくて、
nginxでproxyを書くのにどうするかって話ですが、
ポイントは静的ファイルの扱いです


単純にunicornへリクエストを流そうとすると、
CSSやJSファイルが見つかりませんΣ(゚Д゚)ガーン
まあ、当然の動作ですが・・・


そんなわけでconfigはこんな記述に

    upstream app.hogehoge.piyo {
        server 127.0.0.1:8080;
    }

    server {
        listen  80;
        server_name     hogehoge.piyo;

        location ~* \.(html|ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
                root    public;
                break;
        }

        location / {
                if (-f $request_filename) { break; }
                proxy_set_header X-Real-IP  $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_pass http://app.hogehoge.piyo;
        }
    }

ちなみに、「root public」はRails3アプリのpublicを指しています

# ln -s /path/to/app/public /usr/local/nginx/public


なので、いちいちどこかにファイルをコピーしなくてもOKです
もちろん、一つのサーバで複数動かす場合はpathを工夫してください

結果


メモリが512MBしかないVPSにもかかわらず、
恐ろしいほど高速でしたΣ(゚Д゚;≡;゚д゚)


もちろん一人しかアクセスしてないのもありますが、
リソースが潤沢な開発機でWebrickを動かすよりも、
レスポンスの速度が圧倒的でした


passengerの方が長く使われており、
細かな運用ノウハウがあるのは間違いないと思いますが、
一度nginx+unicornの速度を体感すると、もう戻れないかも


本当は実際に動かしているサイトを見せられればいいのですが、
まだ完成していないので、リリースしたらまた(`・ω・´)ノ

追記(2011/8/18)


リリースしたサイトについて書きました(´・ω・)っ


Rails3で「ROプレイヤーのための占星学サイト」を作ってみた - どっかのBlogの前置きのような

*1:小さいアプリやAPIだとやはりSinatraが楽ですが・・・

*2:Apache+passengerで処理する場合もあれば、Apacheをフロントにしてnginx+passengerをバックエンド、なんてのも