[ベンチ比較] Nodejs : Nginx : PHP

2018年7月5日

テクノロジー 日記

WEBサービスを構築する際に、基盤プラットフォームでの検討を行う事になった。 正直、言語はなんでもいいと考えていたのだが、WEB環境のシンプル構成はLAMPであった方が、色々と都合がいいと考えていたところ、SPA構成でNodejsを使いたいというエンジニアの声があり、とりあえずサーバーレスポンスをベンチして考えてみる事にする。 WIndows OSやMac OSサーバーを使う事はありえず、Linux OSでやる事は間違いないのだが、wordpressなどの導入を前提に考えると、LAMP環境しか有り得ず、各種言語のフレームワークを使うのであれば、言語環境に特化すれば良いだけなのだが、こうした決め事は、決めるべきエンジニアの経験値に依存する事になる。 今回ベンチマークを取ってその後その値だけで決める事はなく、基本的には、下記を比較して決めるのが懸命である。
速度クオリティ 移行のしやすさ 管理の簡易さ

指向性

WEBサービスのプラットフォームは、どういう構造で構築するのが良いかは、以下のような指向で考えたい。
・運用管理効率はLAMPが良い ・Nodejsはモジュール管理でサーバー問題がしょっちゅう発生する。 ・複数の意図しないライブラリを引きずって管理していく事は、メンテデメリットでもある。 ・会社としての開発部門を考えた時に、教育コストを抑えられた方が良い。
個人的には、CGI系は、Nodejs側でwrapできるが、NodejsはCGI系ではwrapしづらいという事も考慮して、基本はLAMPにしておいた方が無難な気がするが、そこはきちんとベンチを計測して判断していきたい。

ベンチ環境

とりあえず、実サーバーで行った方が性格なのだが、同一条件にする事で比較対象にはできるはずなので、下記の仮想環境で行ってみる。
端末 : Mac Booc 1.4GHz OS : Docker ubuntu 14.1 Nodejs : v4.2.6 Nginx : nginx version: nginx/1.10.0 (Ubuntu) PHP-fpm: PHP 7.0.22-0

処理速度のベンチ

単純にNodejsとPHP(fpm)の同じプログラムでの速度差をベンチマークしてみる。

ソースコード

var a = 0, max = 10000000; var start = Date.now(); for (var i = 0; i < max; i++) { a += (i + 2 - 1 * 10 / 3) ; } var end = Date.now(); console.log(end - start); console.log('end: ' + end); console.log('start: ' + start); <?php $a = 0; $max = 10000000; $start = microtime(true)*1000; for ($i = 0; $i < $max; $i++) { $a += ($i + 2 - 1 * 10 / 3) ; } $end = microtime(true)*1000; var_dump($end - $start); var_dump('end: '.$end); var_dump('start: '.$start); var_dump('a: '.$a);

ベンチマーク実行

$ node bench.js 18 end: 1530577777756 start: 1530577777738 $ node bench.js float(205.89086914062) string(18) "end: 1530577822608" string(22) "start: 1530577822402.1" string(17) "a: 49999981664834" この状態では"18:205"でNodejsが10倍以上早い速度結果に見えるが、計測値を同率にするために、Linuxのtimeコマンドで実施してみる。 $ time node bench.js 16 end: 1530577906828 start: 1530577906812 real 0m0.086s user 0m0.060s sys 0m0.020s $ time php bench.php float(207.77514648438) string(20) "end: 1530577938348.9" string(22) "start: 1530577938141.1" string(17) "a: 49999981664834" real 0m0.241s user 0m0.210s sys 0m0.020s 0.086s : 0.241s という結果が出た事により、Nodejsが3倍ほどの速度優位があることがわかる。

htmlソース表示で比較

ソースコード

<!DOCTYPE html> <html> <head> <script src="bench.js"></script> </head> <body> <h1>Bench</h1> </body> </html> var fs = require("fs"); var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); var output = fs.readFileSync("sample.html" , "utf-8"); // var output = "<p>"+ req.url +"</p>"; res.end(output); }).listen(3336); <?php echo file_get_contents("sample.html");

ベンチマーク実行

今回は、Nodejsでは、view.jsを3336ポートで起動しておいて、サイト運用に近い状態を構築する。 その時の100pvアクセスあった事を想定して、"ab(Apache Bench)"コマンドでアクセスしてみる。 あとは、sample.htmlとview.phpそれぞれにアクセスした場合を想定して、「Nginx」 , 「Nginx+PHP(fpm)」の比較も同時に行ってみる。 $ ab -n 1000 http://127.0.0.1:3336/ This is ApacheBench, Version 2.3 < $Revision: 1826891 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Completed 600 requests Completed 700 requests Completed 800 requests Completed 900 requests Completed 1000 requests Finished 1000 requests Server Software: Server Hostname: 127.0.0.1 Server Port: 3336 Document Path: / Document Length: 111 bytes Concurrency Level: 1 Time taken for tests: 4.455 seconds Complete requests: 1000 Failed requests: 0 Total transferred: 211000 bytes HTML transferred: 111000 bytes Requests per second: 224.48 [#/sec] (mean) Time per request: 4.455 [ms] (mean) Time per request: 4.455 [ms] (mean, across all concurrent requests) Transfer rate: 46.26 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.0 0 1 Processing: 2 4 31.9 3 1012 Waiting: 2 4 31.9 3 1012 Total: 2 4 31.9 3 1012 Percentage of the requests served within a certain time (ms) 50% 3 66% 3 75% 4 80% 4 90% 4 95% 5 98% 6 99% 7 100% 1012 (longest request) $ ab -n 1000 http://127.0.0.1/sample.html This is ApacheBench, Version 2.3 < $Revision: 1826891 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Test aborted after 10 failures apr_socket_connect(): Invalid argument (22) yugetakoujinoMacBook:happywall yugeta$ ab -n 1000 http://127.0.0.1:80/sample.html This is ApacheBench, Version 2.3 < $Revision: 1826891 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Test aborted after 10 failures apr_socket_connect(): Invalid argument (22) yugetakoujinoMacBook:happywall yugeta$ ab -n 1000 http://127.0.0.1/sample.html This is ApacheBench, Version 2.3 < $Revision: 1826891 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Completed 600 requests Completed 700 requests Completed 800 requests Completed 900 requests Completed 1000 requests Finished 1000 requests Server Software: nginx/1.10.0 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /sample.html Document Length: 111 bytes Concurrency Level: 1 Time taken for tests: 2.645 seconds Complete requests: 1000 Failed requests: 0 Total transferred: 352000 bytes HTML transferred: 111000 bytes Requests per second: 378.09 [#/sec] (mean) Time per request: 2.645 [ms] (mean) Time per request: 2.645 [ms] (mean, across all concurrent requests) Transfer rate: 129.97 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.0 0 1 Processing: 2 2 0.8 2 13 Waiting: 2 2 0.8 2 13 Total: 2 3 0.8 2 13 WARNING: The median and mean for the total time are not within a normal deviation These results are probably not that reliable. Percentage of the requests served within a certain time (ms) 50% 2 66% 3 75% 3 80% 3 90% 4 95% 4 98% 5 99% 6 100% 13 (longest request) $ ab -n 1000 http://127.0.0.1/view.php This is ApacheBench, Version 2.3 < $Revision: 1826891 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Completed 600 requests Completed 700 requests Completed 800 requests Completed 900 requests Completed 1000 requests Finished 1000 requests Server Software: nginx/1.10.0 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /view.php Document Length: 111 bytes Concurrency Level: 1 Time taken for tests: 4.304 seconds Complete requests: 1000 Failed requests: 0 Total transferred: 257000 bytes HTML transferred: 111000 bytes Requests per second: 232.34 [#/sec] (mean) Time per request: 4.304 [ms] (mean) Time per request: 4.304 [ms] (mean, across all concurrent requests) Transfer rate: 58.31 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.0 0 0 Processing: 3 4 3.8 4 120 Waiting: 3 4 3.8 4 120 Total: 3 4 3.8 4 120 Percentage of the requests served within a certain time (ms) 50% 4 66% 4 75% 4 80% 5 90% 5 95% 6 98% 7 99% 9 100% 120 (longest request) 数値の羅列だけで意味が分からない為少し解説すると、以下のような数値です。 処理時間
Nodejs : 1012 ms Nginx : 13 ms PHP : 120 ms
Nodejsは、ポート待ち受けをして、fsライブラリを使う為、段階が劇的に増えてしまったんでしょうね。 単純計算処理であれば、圧勝だったのに、HTMLソース表示は難ありな感じでした。

まとめ

プラットフォームは、どれか1つに決めずに、処理品質の高い物を部分的に使うのが、サービス提供には一番向いていると改めて思いました。 ただし、メンテナンスコストを考えるとどれか一つにした方がトラブル回避にも繋がります。 WEBサービスの基本はLAMPに任せて、SocketIOや、特殊なサーバーサイドJSを使うたい時にNodejsサーバー(同梱でも別立てでも可)を使うのが良いのではないでしょうか? ちなみに、LAMPもPHP以外でもPythonやRubyやPerlでこだわってみるのも良いし、Goなどのコンパイル言語でゴリっと書き込んでみるのも楽しいかもしれませんね。 この辺は、機能追加や回収コストは高くつきそうですが・・・ どれを選ぶにしても一度作り始めるとなかなか変更ができないだけで、初期段階でしっかり検討しておきたいところですね。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。