JRuby と CRuby の Rails アプリの性能比 (render :text にて)

Thin とか GlassFish とか気になってはいたんですが、自身の体感として分かっていなかったので、簡単なところで比べてみました。"render :text => ... "のスループットをみてますが、絶対値的な性能ではなく、相対的な感覚を掴みたくてやってみました。


環境

  • 処理系、ライブラリのバージョンは以下のとおり
% ruby186 -v
ruby 1.8.6 (2008-08-11 patchlevel 287) [i686-darwin9.6.0]
% ruby187 -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9.5.0]

% jruby -v
jruby 1.1.6RC1 (ruby 1.8.6 patchlevel 114) (2008-12-03 rev 8263) [i386-java]
% java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06-153)
Java HotSpot(TM) 64-Bit Server VM (build 1.6.0_07-b06-57, mixed mode)

% $GLASSFISH_HOME/bin/asadmin version
[GlassFish v3.0-Prelude Prelude (build b28c)]
% $GLASSFISH_HOME/bin/asadmin version
バージョン = Sun GlassFish Enterprise Server v2.1


% gem list --local

*** LOCAL GEMS ***

glassfish (0.9.1)
jetty-rails (0.8)
mongrel (1.1.5)
mongrel_jcluster (0.0.1)
rails (2.2.2,2.1.2)
thin (1.0.0)
warbler (0.9.12)
...

# 目ぼしいものを適当に抜粋

測り方

  • render :text => 'Hello world!' するだけのアクションを用意
  • データベースに問い合わせる処理はまた今度
  • あたり前だけど production モード
  • せっかくなので config.threadsafe! を uncomment
  • 同一筐体から apache bench で負荷
    • % ab -c 10 -n 10000 アプリのURL
  • アプリケーションサーバごとのスループットを観察
    • 絶対値より相対的な性能差をみるのが主目的

結果

組み合わせ Requests per second (mean) 基準化 Time per request (mean)
処理系+APサーバ [#/sec] 基準値を 100 として換算 [ms]
ruby186 + mongrel 309.64 100 3.230
ruby186 + mongrel* 450.91 146 2.218
ruby186 + mongrel** 305.48 99 3.274
ruby187 + mongrel 308.39 100 3.243
ruby186 + thin 455.60 147 2.195
jruby + webrick 137.71 44 7.261
jruby + webrick** 153.62 50 6.509
jruby + jetty-rails 185.49 60 5.391
jruby + glassfish-v3-p 323.79 105 3.088
jruby + glassfish-v3-p** 240.05 78 4.166
jruby + glassfish-v2.1 373.67 121 2.676

注1: * の部分は、rails 2.1.2 で計測したもの。ほかはすべて 2.2.2。
注2: ** の部分は、config.threadsafe! オプションをコメントアウトのままにして計測。
注3: jruby + mongrel も試してみたかったが、jrubycli がないというエラーがでる。バグらしい


所感

  • render :text => ... で比較すると、
  • rails-2.2.2 は rails-2.1.2 より遅かった
  • threadsafe オプションの影響はまだなんとも言えない (あとで詳しくみてみよう)
  • thin サーバ、速っ!
  • jruby + glassfish もけっこうがんばってる
    • でも、フットプリントはでかい
    • glassfish-v3-prelude では使用メモリが増えてくると性能が劣化... (-Xmx オプションの設定かな?)
    • glassfish-v2.1 は安定、かつスループットもよい
  • マルチコア環境で複数インスタンス用意したときの性能も比べてみたい

作業ログ (適当に抜粋)

% ruby186 script/server -e production
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails 2.2.2 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with production environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no restart).
** Rails signals registered.  HUP => reload (without restart).  It might not work well.
** Mongrel 1.1.5 available at 0.0.0.0:3000
** Use CTRL-C to stop.
    • 起動時のメモリ使用量は 30MB弱
    • ab 実行時は CPU 98%前後、メモリ 31MB前後
% ruby186 script/server -e production
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails 2.1.2 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with production environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no restart).
** Rails signals registered.  HUP => reload (without restart).  It might not work well.
** Mongrel 1.1.5 available at 0.0.0.0:3000
** Use CTRL-C to stop.
    • 起動時のメモリ使用量は 30MB弱 (2.2.2 よりは気持ち小さい)
    • ab 実行時は CPU 98%前後、メモリ 31MB前後
% ruby187 script/server -e production
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails 2.2.2 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with production environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no restart).
** Rails signals registered.  HUP => reload (without restart).  It might not work well.
** Mongrel 1.1.5 available at 0.0.0.0:3000
** Use CTRL-C to stop.
    • 起動時のメモリ使用量は 30MB弱
    • ab 実行時は CPU 98%前後、メモリ 31MB前後
  • ruby186 + thin
% thin start -e production
>> Using rails adapter
>> Thin web server (v1.0.0 codename That's What She Said)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:3000, CTRL+C to stop
    • 起動時のメモリ使用量は 30MB弱
    • ab 実行時は CPU 94%前後、メモリ 32MB前後
% jruby script/server -e production
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
=> Booting WEBrick...
=> Rails 2.2.2 application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2009-01-27 18:33:31] INFO  WEBrick 1.3.1
[2009-01-27 18:33:31] INFO  ruby 1.8.6 (2008-12-03) [java]
[2009-01-27 18:33:36] INFO  WEBrick::HTTPServer#start: pid=76137 port=3000
    • 起動時のメモリ使用量は 71MB弱
    • ab 実行時は CPU 160%前後、メモリ 150MBくらいまで着々と上昇
    • ab 実行後のメモリは 154MB
% jruby -S jetty_rails -e production
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
2009-01-27 18:54:19.927::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog
Starting server 3000
2009-01-27 18:54:20.124::INFO:  jetty-6.1.14
2009-01-27 18:54:20.886:/:INFO:  Info: using runtime pool timeout of 30 seconds
2009-01-27 18:54:20.886:/:INFO:  Info: received min runtimes = 1
2009-01-27 18:54:20.886:/:INFO:  Info: received max runtimes = 5
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
2009-01-27 18:54:26.04:/:INFO:  Info: add application to the pool. size now = 1
2009-01-27 18:54:26.072::INFO:  Started SelectChannelConnector@0.0.0.0:3000
    • 起動時のメモリ使用量は 105MB
    • ab 実行時は CPU 160%前後、メモリ 320MBくらいまで着々と上昇
    • ab 実行後のメモリは 322MB
% $GLASSFISH_HOME/bin/asadmin start-domain

% jruby -S warble
cp config/environment.rb tmp/war/WEB-INF/config/environment.rb
cp config/environments/production.rb tmp/war/WEB-INF/config/environments/production.rb
mkdir -p tmp/war/WEB-INF
% $GLASSFISH_HOME/bin/asadmin deploy hoge.war
コマンド deploy は正常に実行されました。

% $GLASSFISH_HOME/bin/asadmin stop-domain
    • glassfish 起動時で、76MB
    • war ファイルの deploy 後で、220MB
    • ab 実行時は CPU 180%前後、メモリ 360MBくらいまで着々と上昇
    • ab 実行後のメモリは 364MB
    • glassfish を起動したまま、2回目の ab をかけると倍くらいの性能
    • 結果として載せているのは、3回目のもの
    • ab を繰り返しかけていくと、メモリ使用量は上昇、性能がでなくなってくる...
    • (追記: 2009-01-28)
    • この組み合わせのもとで、もっかい ab を繰り返しかけてみる
Requests per second:    138.82 [#/sec] (mean) # 1回目 (使用メモリ 368MB に到達)
Requests per second:    308.44 [#/sec] (mean) # 2回目 (使用メモリ 444MB に到達)
Requests per second:    331.52 [#/sec] (mean) # 3回目 (使用メモリ 466MB に到達)
Requests per second:    206.12 [#/sec] (mean) # 4回目 (使用メモリ 518MB に到達)
Requests per second:    187.02 [#/sec] (mean) # 5回目 (使用メモリ 550MB に到達)
Requests per second:    178.27 [#/sec] (mean) # 6回目 (使用メモリ 579MB に到達)
Requests per second:    166.90 [#/sec] (mean) # 7回目 (使用メモリ 610MB に到達)
Requests per second:    123.10 [#/sec] (mean) # 8回目 (使用メモリ 629MB に到達)
Requests per second:    72.44 [#/sec] (mean)  # 9回目 (使用メモリ 629MB のまま)
Requests per second:    58.24 [#/sec] (mean)  # 10回目 (使用メモリ 629MB のまま)
    • メモリ使用の増加にともなって劣化
    • 空きメモリはあったけど、java プロセスのメモリは頭打ちになった
    • デフォルトだと -Xmx 512m になってるからかな?
  • jruby + glassfish-v3-p**
    • config/environments/production.rb を書き替えたのち、上記と同じ
    • ab を何度もかけていった結果
Requests per second:    151.28 [#/sec] (mean) # 1回目
Requests per second:    228.21 [#/sec] (mean) # 2回目
Requests per second:    240.05 [#/sec] (mean) # 3回目
Requests per second:    181.32 [#/sec] (mean) # 4回目
Requests per second:    155.52 [#/sec] (mean) # 5回目
Requests per second:    145.33 [#/sec] (mean) # 6回目 (使用メモリは600MBくらい)


(追記: 2009-01-28)

% java -Xmx256m -jar glassfish-installer-v2.1-b60e-darwin-ml.jar
% cd glassfish
% chmod -R +x lib/ant/bin
% lib/ant/bin/ant -f setup.xml
% bin/asadmin version
バージョン = Sun GlassFish Enterprise Server v2.1
% bin/asadmin start-domain

% $GLASSFISH_HOME_v21/bin/asadmin deploy hoge.war
コマンド deploy は正常に実行されました。
    • 起動 & 配備後のメモリは 260MB
    • ab を何度もかけていった結果
Requests per second:    309.77 [#/sec] (mean) #  1回目 (使用メモリ 304MB に到達)
Requests per second:    361.46 [#/sec] (mean) #  2回目 (使用メモリ 343MB に到達)
Requests per second:    373.67 [#/sec] (mean) #  3回目 (使用メモリ 355MB に到達)
Requests per second:    369.09 [#/sec] (mean) #  4回目 (使用メモリ 373MB に到達)
Requests per second:    370.19 [#/sec] (mean) #  5回目 (使用メモリ 391MB に到達)
Requests per second:    362.62 [#/sec] (mean) #  6回目 (使用メモリ 416MB に到達)
Requests per second:    371.15 [#/sec] (mean) #  7回目 (使用メモリ 417MB に到達)
Requests per second:    372.59 [#/sec] (mean) #  8回目 (使用メモリ 432MB に到達)
Requests per second:    369.12 [#/sec] (mean) #  8回目 (使用メモリ 447MB に到達)
Requests per second:    371.53 [#/sec] (mean) # 10回目 (使用メモリ 464MB に到達)
Requests per second:    346.91 [#/sec] (mean) # 11回目 (使用メモリ 502MB に到達)
Requests per second:    370.91 [#/sec] (mean) # 12回目 (使用メモリ 502MB に到達)
Requests per second:    373.10 [#/sec] (mean) # 13回目 (使用メモリ 502MB に到達)
Requests per second:    372.93 [#/sec] (mean) # 14回目 (使用メモリ 514MB に到達)
Requests per second:    373.43 [#/sec] (mean) # 15回目 (使用メモリ 526MB に到達)
Requests per second:    356.92 [#/sec] (mean) # 16回目 (使用メモリ 551MB に到達)
Requests per second:    365.73 [#/sec] (mean) # 17回目 (使用メモリ 551MB に到達)
Requests per second:    265.37 [#/sec] (mean) # 18回目 (使用メモリ 568MB に到達)
Requests per second:    249.14 [#/sec] (mean) # 19回目 (使用メモリ 568MB に到達)
Requests per second:    219.37 [#/sec] (mean) # 20回目 (使用メモリ 570MB に到達)
    • % ab -c 10 -n 10000 ... で実行したので、断続的に 20万リクエス
    • glassfish-v3-prelude と比較するとおおいに安定
    • 空きメモリがなくなってきた頃合いで頭打ち?
    • スループット的には、CRuby + Mongrel よりもよい結果 (約2割増)