Подтвердить что ты не робот

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

Я сравниваю производительность Node.js(0.5.1-pre) vs Apache (2.2.17) для очень простого сценария - показ текстового файла.

Здесь код, который я использую для сервера node:

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 с экземпляром node это время выполнения:

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. Я замечаю, что node concurrency лучше - при увеличении количества одновременных запросов до 1000 Apache начинает отбрасывать несколько из них, а node отлично работает с никакие соединения не упали.

4b9b3361

Ответ 1

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

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

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

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

Слайд 15 из 45:

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

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

Слайд 16 из 45

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

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

CDN

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

Nginx (+ Memcached)

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

Ответ 2

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

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

Ответ 3

Результат вашего теста может измениться в пользу node.js, если вы увеличиваете concurrency и используете кеш в 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!');
});

Ответ 4

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

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

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

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

Ответ 5

$ 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

Ответ 6

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

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, 12G оперативной памяти.

$ 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