論文や発表が少し落ち着いたので、研究の実装を再開しています。
そこでふと思ったのですが、そういえばngx_mrubyとlua-nginx-moduleのパフォーマンス比較していないなぁと思いました。でも、今検証環境が色々あって揃っていないので微妙だなぁと思いつつも、やっぱり気になると試さずにはいられないたちなので、簡単なhello worldのベンチマーク比較をしてみました。
ngx_mrubyとlua-nginx-moduleの導入
検証環境がないので一から導入しました。意外と簡単ですね。
[program lang=’bash’ escaped=’true’]
wget http://nginx.org/download/nginx-1.4.3.tar.gz tar xvf nginx-1.4.3.tar.gz git clone git@github.com:matsumoto-r/ngx_mruby.git cd ngx_mruby git submodule init git submodule update ./configure --with-ngx-src-root=../nginx-1.4.3 --with-ngx-config-opt="--prefix=/usr/local/nginx143" make build_mruby cd .. git clone https://github.com/chaoslawful/lua-nginx-module.git git clone https://github.com/simpl/ngx_devel_kit.git cd nginx-1.4.3 ./configure --prefix=/usr/local/nginx143 --add-module=../ngx_devel_kit --add-module=../ngx_mruby --add-module=../lua-nginx-module
[/program]
とまぁ、大体こんな感じですぐにインストールできました。
続いて、以下のような設定をnginx.confに書きました。
[program lang=’text’ escaped=’true’]
location /lua { content_by_lua 'ngx.say("hello lworld")'; } location /mruby { mruby_content_handler_code 'Nginx.rputs "hello mworld¥n"'; }
[/program]
/luaにアクセスしたらlua-nginx-moduleでhello worldして、/mrubyにアクセスするとngx_mrubyでhello worldする最もシンプルな処理です。では、これらに対していつものようにベンチマークしてみましょう。
ベンチマーク
今回は、いつもの検証環境がないので、localhost向けでabコマンドを実行しました。ホストはCPUコア1つ、メモリ1GB、NIC1Gbpsの仮想環境にFedora19をいれました。
また、HTMLの出力は同一の13バイトに合わしていますが、それぞれのモジュールでデフォルトのHTTPレスポンスヘッダが違うので、トータルの転送量は微妙に変わります。それらを考慮した上で、以下のベンチマーク結果を見ると良いと思います。keepaliveの有無と同時接続数100総接続数10万でrequest/secを計測しました。
lua-nginx-module
keepalive無し
[program lang=’text’ ]
$ /usr/local/apache/bin/ab -c 100 -n 100000 http://127.0.0.1/lua Server Software: nginx/1.4.3 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /lua Document Length: 13 bytes Concurrency Level: 100 Time taken for tests: 7.197 seconds Complete requests: 100000 Failed requests: 0 Write errors: 0 Total transferred: 16900000 bytes HTML transferred: 1300000 bytes Requests per second: 13894.30 [#/sec] (mean) Time per request: 7.197 [ms] (mean) Time per request: 0.072 [ms] (mean, across all concurrent requests) Transfer rate: 2293.10 [Kbytes/sec] received
[/program]
keepalive有り
[program lang=’text’ escaped=’true’]
$ /usr/local/apache/bin/ab -k -c 100 -n 100000 http://127.0.0.1/lua Server Software: nginx/1.4.3 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /lua Document Length: 13 bytes Concurrency Level: 100 Time taken for tests: 2.691 seconds Complete requests: 100000 Failed requests: 0 Write errors: 0 Keep-Alive requests: 99006 Total transferred: 17395030 bytes HTML transferred: 1300000 bytes Requests per second: 37156.92 [#/sec] (mean) Time per request: 2.691 [ms] (mean) Time per request: 0.027 [ms] (mean, across all concurrent requests) Transfer rate: 6311.97 [Kbytes/sec] received
[/program]
ngx_mruby
keepalive無し
[program lang=’text’ escaped=’true’]
$ /usr/local/apache/bin/ab -c 100 -n 100000 http://127.0.0.1/mruby Server Software: nginx/1.4.3 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /mruby Document Length: 13 bytes Concurrency Level: 100 Time taken for tests: 5.148 seconds Complete requests: 100000 Failed requests: 0 Write errors: 0 Total transferred: 12900000 bytes HTML transferred: 1300000 bytes Requests per second: 19423.42 [#/sec] (mean) Time per request: 5.148 [ms] (mean) Time per request: 0.051 [ms] (mean, across all concurrent requests) Transfer rate: 2446.90 [Kbytes/sec] received
[/program]
keepalive有り
[program lang=’text’ escaped=’true’]
$ /usr/local/apache/bin/ab -k -c 100 -n 100000 http://127.0.0.1/mruby Server Software: nginx/1.4.3 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /mruby Document Length: 13 bytes Concurrency Level: 100 Time taken for tests: 1.991 seconds Complete requests: 100000 Failed requests: 0 Write errors: 0 Keep-Alive requests: 99001 Total transferred: 13395005 bytes HTML transferred: 1300000 bytes Requests per second: 50227.56 [#/sec] (mean) Time per request: 1.991 [ms] (mean) Time per request: 0.020 [ms] (mean, across all concurrent requests) Transfer rate: 6570.30 [Kbytes/sec] received
[/program]
このような結果になりました。結果だけ見ると、この環境でのこのベンチマーク方法ではngx_mrubyの方が1.4倍くらい速い事になります。表にまとめると以下のようになります。
Request/sec | ||
ngx_mruby | lua-nginx-module | |
keepalive無し | 19423.42 | 13894.30 |
keepalive有り | 50227.56 | 37156.92 |
対象のコンテンツをhello world程度の軽量な処理にすることで、インタプリタに関連する処理の影響を最大限にすることが今回のベンチマークの目的です。ngx_mrubyは基本的にmod_mrubyで考えた高速かつ省メモリなアーキテクチャで実装しているので、機能面や使いやすさを前提としたときに、今思いつく限りでの高速な実装になっています。その辺りは論文でも書いているので、また公開します。
luaとmrubyの言語としての速度はluaの方が現段階では速いと思うので、今回lua-nginx-moduleが遅かったのはインタプリタ組み込みアーキテクチャにおける性能差のように推測します。その辺りについては、今後lua-nginx-moduleのコードを追っていきたいと思います。
まとめ
単純なhello worldの比較ではngx_mrubyの方が速い結果となりました。しかし、lua-nginx-moduleには沢山機能があって、安定稼働している例もいくつか聞くので、まだまだ複雑な事をやろうとするとlua-nginx-moduleの方が良いでしょう。また、コルーチンを使ったasync+non-blockingな動きを実装済み(lua-nginx-module の紹介 ならびに Nginx+Lua+Redisによる動的なリバースプロキシの実装案)ですので、その辺りでも優位性があります。しかし、そろそろngx_mrubyでできるような処理(ngx_mrubyの紹介 ならびに nginx+mruby+Redisによる動的なリバースプロキシの実装案)であれば、ngx_mrubyを使う選択肢も出てきたのではないでしょうか。
ngx_mrubyの今後の実装方針としては、このようなパフォーマンスを低下させることなく、mod_mrubyの機能をベースに機能追加していきたいと思います。少なくとも、ngx_mrubyとmod_mrubyはできるだけ同じようなDSL記述が可能になるように工夫していく予定です。