web-dev-qa-db-ja.com

Node.jsはApacheより遅い

非常に単純なシナリオ(テキストファイルの提供)について、Node.js(0.5.1-pre)とApache(2.2.17)のパフォーマンスを比較しています。

ノードサーバーに使用するコードは次のとおりです。

var http = require('http')
  , fs = require('fs')

fs.readFile('/var/www/README.txt',
    function(err, data) {
        http.createServer(function(req, res) {
            res.writeHead(200, {'Content-Type': 'text/plain'})
            res.end(data)
        }).listen(8080, '127.0.0.1')
    }
)

Apacheの場合、Ubuntu11.04に対応するデフォルト構成を使用しています。

Apacheに対して次のパラメータを使用してApacheBenchを実行する場合

ab -n10000 -c100 http://127.0.0.1/README.txt

次のランタイムを取得します。

Time taken for tests:   1.083 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      27630000 bytes
HTML transferred:       24830000 bytes
Requests per second:    9229.38 [#/sec] (mean)
Time per request:       10.835 [ms] (mean)
Time per request:       0.108 [ms] (mean, across all concurrent requests)
Transfer rate:          24903.11 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.8      0       9
Processing:     5   10   2.0     10      23
Waiting:        4   10   1.9     10      21
Total:          6   11   2.1     10      23

Percentage of the requests served within a certain time (ms)
  50%     10
  66%     11
  75%     11
  80%     11
  90%     14
  95%     15
  98%     18
  99%     19
 100%     23 (longest request)

nodeインスタンスに対してApacheベンチを実行する場合、これらはランタイムです。

Time taken for tests:   1.712 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      25470000 bytes
HTML transferred:       24830000 bytes
Requests per second:    5840.83 [#/sec] (mean)
Time per request:       17.121 [ms] (mean)
Time per request:       0.171 [ms] (mean, across all concurrent requests)
Transfer rate:          14527.94 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.9      0       8
Processing:     0   17   8.8     16      53
Waiting:        0   17   8.6     16      48
Total:          1   17   8.7     17      53

Percentage of the requests served within a certain time (ms)
  50%     17
  66%     21
  75%     23
  80%     25
  90%     28
  95%     31
  98%     35
  99%     38
 100%     53 (longest request)

これは明らかにApacheよりも遅いです。 Apacheがロギングなどの他の多くのことを行っているという事実を考えると、これは特に驚くべきことです。

私はそれを間違っていますか?または、このシナリオではNode.jsは本当に遅いですか?

編集1:ノードの同時実行性が優れていることに気付きました-同時リクエストの数を1000に増やすと、Apacheはそれらのいくつかをドロップし始めますが、ノードは接続がドロップされずに正常に動作します。

26
Art

動的リクエスト

node.jsは、多くの小さな動的リクエスト(ハング/ロングポーリングの可能性がある)での処理に非常に優れています。ただし、大きなバッファの処理は得意ではありません。 Ryan Dahl(Author node.js)は、これについて 彼のプレゼンテーション について説明しました。これらのスライドを研究することをお勧めします。私もどこかでこれをオンラインで見ました。

ガベージコレクター

スライド(45から13)からわかるように、大きなバッファーには適していません。

45から15のスライド:

V8には世代別ガベージコレクターがあります。オブジェクトをランダムに移動します。 Nodeソケットに書き込む生の文字列データへのポインタを取得できません。

バッファを使用する

45から16をスライド

Nodeの新しいBufferオブジェクトを使用すると、結果が変わります。

それでも、たとえばnginxほど良くはありませんが、はるかに優れています。また、これらのスライドはかなり古いので、おそらくライアンはこれを改善しました。

CDN

それでも、静的ファイルをホストするためにnode.jsを使用するべきではないと思います。静的ファイルをホストするために最適化されたCDNでそれらをホストする方がおそらく良いでしょう。 いくつかの人気のあるCDN の(いくつかは無料です)WIKI経由。

NGinx(+ Memcached)

CDNを使用して静的ファイルをホストしたくない場合は、代わりに Nginx with memcached を使用することをお勧めします。これは非常に高速です。

25
Alfred

このシナリオでは、Apacheはおそらく sendfile を実行しているため、カーネルはメモリデータのチャンク(fsドライバーによってキャッシュされます)をソケットに直接送信します。ノードの場合、v8、libeio、カーネルの間でユーザースペースのデータをコピーする際にオーバーヘッドが発生します(ノードでのsendfileの使用に関する素晴らしい記事 this を参照)

「可能な限り多くのtcp接続に一定の低速でデータのストリームを送信する」など、ノードがApacheを上回る可能性のあるシナリオはたくさんあります。

20
Andrey Sidorov

並行性を高め、node.jsでキャッシュを使用すると、ベンチマークの結果がnode.jsに有利に変わる可能性があります

「ノードクックブック」という本のサンプルコード:

var http = require('http');
var path = require('path');
var fs = require('fs');
var mimeTypes = {
    '.js' : 'text/javascript',
    '.html': 'text/html',
    '.css' : 'text/css'
} ;
var cache = {};
function cacheAndDeliver(f, cb) {
    if (!cache[f]) {
        fs.readFile(f, function(err, data) {
            if (!err) {
                cache[f] = {content: data} ;
            }
            cb(err, data);
        });
        return;
    }
    console.log('loading ' + f + ' from cache');
    cb(null, cache[f].content);
}
http.createServer(function (request, response) {
    var lookup = path.basename(decodeURI(request.url)) || 'index.html';
    var f = 'content/'+lookup;
    fs.exists(f, function (exists) {
        if (exists) {
            fs.readFile(f, function(err,data) {
                if (err) { response.writeHead(500);
                    response.end('Server Error!'); return; }
                    var headers = {'Content-type': mimeTypes[path.extname(lookup)]};
                    response.writeHead(200, headers);
                    response.end(data);
                });
            return;
        }
response.writeHead(404); //no such file found!
response.end('Page Not Found!');
});
3
egiray

ここで実際に行っているのは、異なるプロセスのアドレス空間にあるメモリ内のバッファ間でデータをコピーすることだけです。ディスクキャッシュは、実際にはディスクに触れておらず、ローカルソケットを使用していることを意味します。

したがって、リクエストごとに実行する必要のあるコピーが少ないほど、処理は速くなります。

編集:キャッシュを追加することを提案しましたが、実際にはすでにそれを行っていることがわかります-ファイルを1回読み取り、サーバーを起動して、毎回同じバッファーを送り返します。

ヘッダー部分をファイルデータに事前に追加しようとしたので、リクエストごとに1回の書き込み操作を実行するだけで済みますか?

1
$ cat /var/www/test.php
<?php
for ($i=0; $i<10; $i++) {
        echo "hello, world\n";
}


$ ab -r -n 100000 -k -c 50 http://localhost/test.php
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
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 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests


Server Software:        Apache/2.2.17
Server Hostname:        localhost
Server Port:            80

Document Path:          /test.php
Document Length:        130 bytes

Concurrency Level:      50
Time taken for tests:   3.656 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    100000
Total transferred:      37100000 bytes
HTML transferred:       13000000 bytes
Requests per second:    27350.70 [#/sec] (mean)
Time per request:       1.828 [ms] (mean)
Time per request:       0.037 [ms] (mean, across all concurrent requests)
Transfer rate:          9909.29 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       3
Processing:     0    2   2.7      0      29
Waiting:        0    2   2.7      0      29
Total:          0    2   2.7      0      29

Percentage of the requests served within a certain time (ms)
  50%      0
  66%      2
  75%      3
  80%      3
  90%      5
  95%      7
  98%     10
  99%     12
 100%     29 (longest request)

$ cat node-test.js 
var http = require('http');
http.createServer(function (req, res) {
          res.writeHead(200, {'Content-Type': 'text/plain'});
            res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');

$ ab -r -n 100000 -k -c 50 http://localhost:1337/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
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 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests


Server Software:        
Server Hostname:        localhost
Server Port:            1337

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      50
Time taken for tests:   14.708 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      7600000 bytes
HTML transferred:       1200000 bytes
Requests per second:    6799.08 [#/sec] (mean)
Time per request:       7.354 [ms] (mean)
Time per request:       0.147 [ms] (mean, across all concurrent requests)
Transfer rate:          504.62 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       3
Processing:     0    7   3.8      7      28
Waiting:        0    7   3.8      7      28
Total:          1    7   3.8      7      28

Percentage of the requests served within a certain time (ms)
  50%      7
  66%      9
  75%     10
  80%     11
  90%     12
  95%     14
  98%     16
  99%     17
 100%     28 (longest request)

$ node --version
v0.4.8
0
mschwartz

以下のベンチマークでは、

Apache:

$ Apache2 -version
Server version: Apache/2.2.17 (Ubuntu)
Server built:   Feb 22 2011 18:35:08

PHPAPCキャッシュ/アクセラレータがインストールされています。

私のラップトップ、Core I7 920、12GのRAMを搭載したSagerNP9280でテスト実行します。

$ uname -a
Linux presto 2.6.38-8-generic #42-Ubuntu SMP Mon Apr 11 03:31:24 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux

KUbuntu natty

0
mschwartz