Node.js медленнее, чем Apache - PullRequest
       13

Node.js медленнее, чем Apache

26 голосов
/ 09 июля 2011

Я сравниваю производительность 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 я просто использую любую конфигурацию по умолчанию, которая идет с Ubuntu 11.04

При запуске Apache Bench со следующими параметрами для Apache

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)

При запуске Apache Bench для экземпляра узла это среды выполнения:

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 действительно медленнее в этом сценарии?

Edit 1 : я заметил, что параллелизм узла лучше - при увеличении количества одновременных запросов до 1000, Apache начинает отбрасывать несколькоих, в то время как узел работает нормально, без потери соединений.

Ответы [ 6 ]

25 голосов
/ 09 июля 2011

Динамические запросы

node.js очень хорошо справляется с небольшими динамическими запросами (которые могут зависать / долго опрашиваться). Но он плохо справляется с большими буферами. Райан Даль (Автор node.js) объяснил это одной из своих презентаций . Я рекомендую вам изучить эти слайды. Я тоже где-то смотрел онлайн.

Сборщик мусора

Как видно из слайда (13 из 45), он плохо работает с большими буферами.

Слайд 15 из 45:

В V8 есть мусор поколений коллектор. Перемещает объекты вокруг случайным образом. Узел не может получить указатель на необработанные строковые данные для записи в сокет.

Использовать буфер

Слайд 16 из 45

Используя новый объект буфера Node, результаты меняются.

Все еще не так хорошо, как, например, nginx, но намного лучше. Также эти слайды довольно старые, так что, вероятно, Райан даже улучшил это.

CDN

Тем не менее, я не думаю, что вы должны использовать node.js для размещения статических файлов. Возможно, вам лучше разместить их на CDN, который оптимизирован для размещения статических файлов. Некоторые популярные CDN (некоторые даже бесплатно) через WIKI.

Nginx (+ Memcached)

Если вы не хотите использовать CDN для размещения ваших статических файлов, я рекомендую вам использовать Nginx с memcached , что очень быстро.

20 голосов
/ 09 июля 2011

В этом сценарии Apache, вероятно, выполняет sendfile , что приводит к тому, что ядро ​​отправляет порцию данных в памяти (кэшируется драйвером fs) непосредственно в сокет. В случае узла есть некоторые издержки при копировании данных в пользовательском пространстве между v8, libeio и ядром (см. эту отличную статью об использовании sendfile в узле)

Существует множество возможных сценариев, в которых узел будет превосходить Apache, например, «отправлять поток данных с постоянной медленной скоростью как можно большему количеству соединений tcp»

3 голосов
/ 24 октября 2012

Результат вашего теста может измениться в пользу node.js, если вы увеличите параллелизм и используете кеш в node.js

Пример кода из книги "Node Cookbook":

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!');
});
1 голос
/ 09 июля 2011

На самом деле все, что вы здесь делаете, это заставляет систему копировать данные между буферами в памяти, в адресных пространствах разных процессов - дисковый кеш означает, что вы не касаетесь диска и используете локальные сокеты.

Таким образом, чем меньше копий нужно сделать для запроса, тем быстрее он идет.

Редактировать: Я предложил добавить кеширование, но на самом деле я вижу, что вы уже делаете это - вы один раз читаете файл, затем запускаете сервер и каждый раз отправляете обратно один и тот же буфер. *

Вы пытались добавить часть заголовка к данным файла сразу, так что вам нужно выполнить только одну операцию записи для каждого запроса?

0 голосов
/ 14 июля 2011

В нижеприведенных тестах

Apache:

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

Установлен PHP APC кеш / ускоритель.

Тестовый запуск на моем ноутбуке, Sager NP9280 с Core I7 920, 12 ГБ ОЗУ.

$ 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 голосов
/ 14 июля 2011
$ 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...