2014-11-06 15 views
9

Falls jemand will versuchen: https://github.com/codependent/cluster-performanceNode.js Cluster nicht verbessert die Leistung erheblich

Ich teste Node.js (v0.11.13 - Windows 7) Anfrage pro Sekunde Grenzen mit einer einfachen Anwendung . Ich habe einen Service mit Express 4 implementiert, der eine E/A-Operation wie eine DB-Abfrage mit einem setTimeout-Callback simuliert.

Zuerst teste ich es mit nur einem Knoten-Prozess. Für den zweiten Test starte ich so viele Arbeiter wie die CPUs der Maschine hat.

ich loadtest bin mit dem Service mit den folgenden Parametern testen:

loadtest -n 50000 -c 220 -k http://localhost:5000/operations/timeout/20 

Das heißt, 50k Gesamt Anfragen, 220 gleichzeitige Clients.

My Dienst setzt den timeout (die Dauer der Bearbeitungszeit) nach dem letzten URL-Parameter (20 MSEG):

router.route('/timeout/:time') 
.get(function(req, res) { 
    setTimeout(function(){ 
     appLog.debug("Timeout completed %d", process.pid); 
     res.json(200,{result:process.pid}); 
    },req.param('time')); 
});  
  1. nur ein Knoten Prozess

These sind die Ergebnisse:

INFO Max requests:  50000 
INFO Concurrency level: 200 
INFO Agent:    keepalive 
INFO 
INFO Completed requests: 50000 
INFO Total errors:  0 
INFO Total time:   19.326443741 s 
INFO Requests per second: 2587 
INFO Total time:   19.326443741 s 
INFO 
INFO Percentage of the requests served within a certain time 
INFO 50%  75 ms 
INFO 90%  92 ms 
INFO 95%  100 ms 
INFO 99%  117 ms 
INFO 100%  238 ms (longest request) 

2580 Anfragen pro Sekunde, nicht schlecht.

  1. n Arbeiter (n = NumCPUs)

In diesem Fall habe ich die Last gleichmäßig unter den Arbeitern mit der Politik Planung Round-Robin verteilen. Da es nun 8 Cores gibt, die Anfragen verarbeiten, erwartete ich eine signifikante Verbesserung (8 mal schneller?) In den Anfragen pro Sekunde, aber es stieg nur auf 2905 rps !!! (318 rps mehr) Wie können Sie das erklären? Mache ich etwas falsch?

Ergebnisse:

Max requests:  50000 
Concurrency level: 220 
Agent:    keepalive 

Completed requests: 50000 
Total errors:  0 
Total time:   17.209989764000003 s 
Requests per second: 2905 
Total time:   17.209989764000003 s 

Percentage of the requests served within a certain time 
    50%  69 ms 
    90%  103 ms 
    95%  112 ms 
    99%  143 ms 
100%  284 ms (longest request) 

Mein Cluster Initialisierungscode:

#!/usr/bin/env node 
var nconf = require('../lib/config'); 
var app = require('express')(); 
var debug = require('debug')('mma-nodevents'); 
var http = require("http") 
var appConfigurer = require('../app'); 
var cluster = require('cluster'); 
var numCPUs = require('os').cpus().length; 

if('v0.11.13'.localeCompare(process.version)>=0){ 
    cluster.schedulingPolicy = cluster.SCHED_RR; 
} 

if (cluster.isMaster) { 
    // Fork workers. 
    for (var i = 0; i < numCPUs; i++) { 
     cluster.fork(); 
    } 
    cluster.on('exit', function(worker, code, signal) { 
     console.log('worker ' + worker.process.pid + ' died'); 
     cluster.fork(); 
    }); 
}else{ 
    console.log("starting worker [%d]",process.pid); 
    appConfigurer(app); 
    var server = http.createServer(app); 
    server.listen(nconf.get('port'), function(){ 
     debug('Express server listening on port ' + nconf.get('port')); 
    }); 

} 

module.exports = app; 

UPDATE:

ich habe endlich slebetman Antwort akzeptiert, da er recht über den Grund, warum in diesem Fall war Die Clusterleistung stieg mit bis zu 8 Prozessen nicht signifikant an. Ich möchte jedoch auf eine interessante Tatsache hinweisen: mit der aktuellen Version io.js (2.4.0), es hat sich wirklich auch für diese hohe I/O-Operation (SetTimeout) verbessert:

loadtest -n 50000 -c 220 -k http://localhost:5000/operations/timeout/20 

Einfaden:

Max requests:  50000 
Concurrency level: 220 
Agent:    keepalive 

Completed requests: 50000 
Total errors:  0 
Total time:   13.391324847 s 
Requests per second: 3734 
Total time:   13.391324847 s 

Percentage of the requests served within a certain time 
    50%  57 ms 
    90%  67 ms 
    95%  74 ms 
    99%  118 ms 
100%  230 ms (longest request) 

8 Kern Cluster:

Max requests:  50000 
Concurrency level: 220 
Agent:    keepalive 

Completed requests: 50000 
Total errors:  0 
Total time:   8.253544166 s 
Requests per second: 6058 
Total time:   8.253544166 s 

Percentage of the requests served within a certain time 
    50%  35 ms 
    90%  47 ms 
    95%  52 ms 
    99%  68 ms 
100%  178 ms (longest request) 

So ist es klar, dass mit den aktuellen io.js/node.js Releases, obwohl Sie nicht eine 8x rps erhöhen bekommen e, der Durchsatz ist fast 1,7 mal schneller.

Auf der anderen Seite, wie erwartet, die Verwendung einer For-Schleife für die in der Anfrage angegebene Anzahl von Millisekunden Iterieren (und damit den Thread blockieren), erhöht sich die RPS proportional zur Anzahl der Threads.

+0

Amdahls Gesetz besagt, dass selbst im optimistischsten Szenario würden Sie nicht die 8-mal Verbesserung erhalten, die Sie suchen. Es gibt viele mögliche Antworten darauf, warum sich Ihre Ergebnisse nicht sehr verbessert haben. Ihre App skaliert entweder nicht gut oder der Server lief nicht wirklich 8 CPUs zur Verfügung usw. – user2717954

+0

Hehe, ich wusste 8x war zu optimistisch. Mit 8 CPUSs, die für einige Arbeiten zur Verfügung stehen, sollte es tatsächlich die rps verbessern, während es die Leistung nicht einmal verdoppelt. Über "Ihre App skaliert nicht", nun können Sie sehen, der Code ist ziemlich einfach: eine Route mit einem SetTimeout(), wie kommt es würde nicht skalieren ... – codependent

Antwort

15

E/A-Operationen sind genau die Art von Anwendung, für die Node.js entwickelt und optimiert wurde. I/O-Operationen (und setTimeout) laufen im Wesentlichen parallel, so wie die Hardware (Netzwerk, Festplatte, PCI-Bridge, DMA-Controller usw.) es zulässt.

Sobald Sie dies erkannt haben, ist es leicht zu verstehen, warum die Ausführung vieler paralleler E/A-Vorgänge in einem einzigen Vorgang ungefähr die gleiche Zeit in Anspruch nimmt wie die Ausführung vieler paralleler E/A-Vorgänge in vielen Prozessen/Threads. In der Tat würde das direkte Analog viele parallele E/A-Operationen in einem Prozess ablaufen lassen, genauso wie das Ausführen einzelner blockierender E/A-Operationen in vielen parallelen Prozessen.

Clustering ermöglicht es Ihnen, mehrere CPUs/Kerne zu verwenden, wenn Sie sie haben. Aber Ihr Prozess verwendet keine CPU-Zyklen. Clustering gibt Ihnen also sehr wenig Vorteil (falls vorhanden).

+0

Um zu sehen, die Art von Vorteil Clustering kann CPU gebunden geben Anwendungen, ersetzen Sie die SetTimeout durch eine for-Schleife. – slebetman

+0

Ich werde es versuchen und melden, danke für die Info! – codependent

0

Haben Sie versucht, das Loadtesting-Programm selbst zwischen zwei oder mehr Prozessen aufzuteilen? Es ist durchaus möglich, dass Sie stattdessen die Grenzen der Loadtest-Anwendung erreicht haben.

-1

Verwenden Sie keine cluster.SCHED_RR, cluster.SCHED+ nur

+0

Fügen Sie einige Erklärungen mit der Antwort hinzu, wie diese Antwort dem aktuellen Problem helfen kann –

0

Ein einfaches Calc verwenden:

1000/20*220 = 11000 // theoretically max request per second 

Sie auf localhost testen, bedeutet dies, verwendet Netzwerkzeit ist winzig, so dass ich denke, log Ausgabeblock ist

Bitte kommentieren Sie es und versuchen Sie es erneut.

Verwandte Themen