at posts/single.html

tDiaryを Nginx + Unicorn + さくらVPSで動かした

さくらVPSがリニューアルしたので、この日記も新しいサーバに引っ越した。ついでに、サーバの構成も変えてみた。

Unicornまで持ち出すのはオーバースペックな気もするけど、面白いから、いい。

インストール

  • Nginx … OSをUbuntu (2012.04 LTS) にしたので apt-get nginx でインストール
  • Ruby … rbenv + ruby-build で 1.9.3 をインストール
  • Unicorn … rbenv環境にてgem install unicorn
  • tDiary … githubからtdiary-coreとtdiary-contribを取得

サイト構成

ドキュメントルートは /var/www/www.machu.jp に設定し、トップページのコンテンツはここに置く。

ただし、tDiary関連のファイルはドキュメントルート以下に置かない。 これがFastCGI経由とUnicorn(というかRackサーバ)経由の一番の違い。

僕は以下のサイト構成にした。

/var/www/www.machu.jp ← トップページの静的コンテンツ
/home/machu/var/tdiary
  tdiary-core/ ← GitHubからtdiary-coreをpull
  tdiary-contrib/ ← GitHubからtdiary-contribをpull
  data/ ← tDiaryの @data_path で指定

Nginxの設定

基本設定は省略。サイトごとの設定 /etc/nginx/site-available/www.machu.jp はこれ。 /diary/ 以下をポート8080へ転送するようにしている。

upstream www.machu.jp {
        server localhost:8080;
}

server {
        root /var/www/www.machu.jp;
        index index.html index.htm;

        server_name www.machu.jp;

        location ~ ^/diary/ {
                rewrite ([0-9\-]+)\.html$ /diary/index.rb?date=$1 last;
                proxy_pass http://www.machu.jp;
        }
}

YYYYMMDD.html を index.rb?date=YYYYMMDD へ書き換えているのもここ。

Unicornの設定

tDiaryの設置場所 /home/machu/var/tdiary/tdiary-core に unicorn の設定ファイル unicorn.conf を作成。 元ネタはUnicornのオフィシャルサイトから入手。

worker_processes 4
listen 8080, :tcp_nopush => true

pid "unicorn.pid"

stderr_path "log/unicorn.stderr.log"
stdout_path "log/unicorn.stdout.log"

preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
  GC.copy_on_write_friendly = true

ポイントはこれくらいか。

  • worker_processes : 起動するプロセス数。メモリと相談して増減。
  • liston : 待ち受けポート番号
  • pid : unicornの起動プロセスIDを書き出すファイル

tDiaryの設定

tDiaryで使用する関連ライブラリを bundle でインストールする。--without オプションを指定して、開発のみで使うライブラリ類を除外する。

$ gem install bundler
$ bundle install  --without test development

次に config.ru を編集。/diary/ディレクトリ以下で動かせるように、 base_dir を指定できるようにした。(これは後で本体に pull request を送る予定)

diff --git a/config.ru b/config.ru
index 4f78176..e00c65d 100644
--- a/config.ru
+++ b/config.ru
@@ -3,7 +3,9 @@ require 'tdiary/application'
 
 use Rack::Reloader
 
-map '/assets' do
+base_dir = '/diary'
+
+map "#{base_dir}/assets" do
        environment = Sprockets::Environment.new
        ['js', 'theme', '../tdiary-contrib/js', '../tdiary-theme'].each do |path|
                environment.append_path path
@@ -11,15 +13,15 @@ map '/assets' do
        run environment
 end
 
-map "/" do
+map "#{base_dir}/" do
        run TDiary::Application.new(:index)
 end
 
-map "/index.rb" do
+map "#{base_dir}/index.rb" do
        run TDiary::Application.new(:index)
 end
 
-map "/update.rb" do
+map "#{base_dir}/update.rb" do
        use Rack::Auth::Basic do |user, pass|
                if File.exist?('.htpasswd')
                        require 'webrick/httpauth/htpasswd'                                                                                          

次に tdiary.conf を編集。contribのプラグインを参照できるように sp.path を設定。あとはいつも通りでOK。

@options['sp.path'] = ["#{TDiary::PATH}/misc/plugin", "#{TDiary::PATH}/../tdiary-contrib/plugin"]

その他

  • 認証ファイルは .htpasswd をそのまま使える。config.ruにて.htpasswdを読み込んでいる。
  • unicorn経由で起動するので FastCGI と違って index.rb や update.rb の shabang 行の編集は不要。

起動

Nginxはinit.dで起動。UnicornはtDiaryのルートへ移動して、unicornコマンドで起動。-cオプションは設定ファイル読み込み。-Dはデーモン化。

$ sudo /etc/init.d/nginx start
$ cd /home/machu/var/tdiary/tdiary-core
$ unicorn -c unicorn.conf -D

いきなりunicornで動かすよりも、まずは ./misc/standalone_cgi/bin/serverrackup を使って単体で動かすのがいいだろう。

停止

Unicornはプロセスへのシグナル送信で操作する。Unicornのマニュアルを参照。

$ cd /home/machu/var/tdiary/tdiary-core
$ kill -HUP `cat unicorn.pid` ← 再起動する場合
$ kill -QUIT `cat unicorn.pid` ← 終了する場合

まだできていないこと

  • 静的ファイルのキャッシュ (今は静的ファイルもUnicorn側で返しているが、Nginx側で返したい)
  • YYYYMMDD.html → index.rb?date=YYYYMMDD の変換を Nginx 側ではなく tDiary のRackレイヤで実施
  • フィード (index.rdf) が読めなくなった

abで測定

ab -n 30 -c 3 で新旧を比較。

これまで(Apache2+FastCGI)。

Requests per second:    1.19 [#/sec] (mean)
Time per request:       2529.478 [ms] (mean)
Time per request:       843.159 [ms] (mean, across all concurrent requests)

変更後(Nginx+Unicorn)

Requests per second:    5.39 [#/sec] (mean)
Time per request:       556.467 [ms] (mean)
Time per request:       185.489 [ms] (mean, across all concurrent requests)

4倍くらい速くなった。でも、サーバも変わったし、起動プロセス数も違うし、どこが効いているのかわからない ← だめな性能測定のパターン

関連する日記