performance apache node.js apache2

performance - Node.js más lento que Apache



apache2 (6)

Solicitudes dinámicas

node.js es muy bueno en el manejo de solicitudes dinámicas pequeñas (que pueden ser suspendidas / largas). Pero no es bueno para manejar buffers grandes. Ryan Dahl (Author node.js) explicó esta una de sus presentaciones . Te recomiendo que estudies estas diapositivas. También vi esto en línea en algún lado.

Recolector de basura

Como se puede ver en la diapositiva (13 de 45), es malo en los buffers grandes.

Diapositiva 15 de 45:

V8 tiene un recolector de basura generacional. Mueve los objetos aleatoriamente. Nodo no puede obtener un puntero a los datos de cadena sin procesar para escribir en el socket.

Usar buffer

Diapositiva 16 de 45

Usando el nuevo objeto Buffer de Node, los resultados cambian.

Todavía no es tan bueno como por ejemplo nginx, pero mucho mejor. Además, estas diapositivas son bastante viejas, por lo que probablemente Ryan haya mejorado esto.

CDN

Aún así, no creo que deba usar node.js para alojar archivos estáticos. Probablemente sea mejor que los aloje en un CDN que está optimizado para alojar archivos estáticos. Algunos CDN populares (algunos incluso gratuitos) a través de WIKI.

NGinx (+ Memcached)

Si no quiere usar CDN para alojar sus archivos estáticos, le recomiendo usar Nginx con memcached, que es muy rápido.

Estoy comparando el rendimiento de Node.js (0.5.1-pre) vs Apache (2.2.17) para un escenario muy simple: servir un archivo de texto.

Aquí está el código que uso para el servidor de nodos:

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'') } )

Para Apache solo estoy usando la configuración predeterminada que acompaña a Ubuntu 11.04

Al ejecutar Apache Bench con los siguientes parámetros contra Apache

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

Obtengo los siguientes tiempos de ejecución:

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)

Cuando se ejecuta el banco Apache contra la instancia del nodo , estos son los tiempos de ejecución:

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)

Que es claramente más lento que Apache. Esto es especialmente sorprendente si se tiene en cuenta el hecho de que Apache está haciendo muchas otras cosas, como el registro, etc.

¿Lo estoy haciendo mal? ¿O es Node.js realmente más lento en este escenario?

Editar 1 : Noto que la concurrencia del nodo es mejor: al aumentar un número de solicitudes simultáneas a 1000, Apache comienza a descartar algunas de ellas, mientras que el nodo funciona bien sin conexiones caídas.


El resultado de su punto de referencia puede cambiar a favor de node.js si aumenta la concurrencia y utiliza la memoria caché en node.js

Un código de muestra del libro "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!''); });


En este escenario, Apache probablemente está haciendo sendfile que da como resultado que kernel envíe fragmentos de datos de memoria (en caché por el controlador fs) directamente al socket. En el caso del nodo, hay una sobrecarga en la copia de datos en el espacio de usuario entre v8, libeio y kernel (consulte this gran artículo sobre el uso de sendfile en el nodo)

Hay muchos escenarios posibles en los que el nodo superará a Apache, como ''enviar flujo de datos con velocidad lenta constante a tantas conexiones tcp como sea posible''


En los puntos de referencia a continuación,

Apache:

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

PHP APC cache / accelerator está instalado.

Prueba de funcionamiento en mi computadora portátil, un Sager NP9280 con Core I7 920, 12G de RAM.

$ 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


En realidad, todo lo que hace aquí es hacer que el sistema copie datos entre memorias intermedias en la memoria, en espacios de direcciones de procesos diferentes: la memoria caché de disco significa que realmente no está tocando el disco y está utilizando conectores locales.

Por lo tanto, cuantas menos copias haya que hacer por solicitud, más rápido irá.

Editar: sugerí que agregue el almacenamiento en caché, pero de hecho ahora veo que ya está haciendo eso: lee el archivo una vez, luego inicia el servidor y devuelve el mismo búfer cada vez.

¿Ha intentado anexar la parte del encabezado a los datos del archivo una vez por adelantado, por lo que solo tiene que hacer una sola operación de escritura para cada solicitud?


$ 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