webentwicklung-frage-antwort-db.com.de

Unerwartetes Ergebnis von node.js im Vergleich zum ASP.NET Core-Leistungstest

Ich mache einen kurzen Stresstest für zwei (irgendwie) Hallo-Welt-Projekte, die in node.js und asp.net-core geschrieben sind. Beide werden im Produktionsmodus und ohne angeschlossenen Logger ausgeführt. Das Ergebnis ist erstaunlich! Der ASP.NET-Kern übertrifft die Leistung der node.js-App, selbst nachdem einige zusätzliche Arbeiten ausgeführt wurden, während die node.js-App nur eine Ansicht rendert.

App 1: http://localhost:3000/nodejsnode.js

Verwenden von : node.js, Express- und Vash-Rendering-Engine.

nodejs app

Der Code in diesem Endpunkt lautet

router.get('/', function(req, res, next) {
  var vm = {
    title: 'Express',
    time: new Date()
  }
  res.render('index', vm);
});

Wie Sie sehen, wird nichts anderes getan, als das aktuelle Datum über die Variable time an die Ansicht zu senden.

App 2: http://localhost:5000/aspnet-coreasp.net core

Verwenden von : ASP.NET Core, Standard-Template-Targeting dnxcore50

Diese App kann jedoch nicht nur eine Seite mit einem Datum rendern. Es werden 5 Absätze mit verschiedenen zufälligen Texten generiert. Dies sollte theoretisch etwas schwerer sein als die nodejs-App.

asp.net core app

Hier ist die Aktionsmethode, mit der diese Seite gerendert wird

[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
[Route("aspnet-core")]
public IActionResult Index()
{
    var sb = new StringBuilder(1024);
    GenerateParagraphs(5, sb);

    ViewData["Message"] = sb.ToString();
    return View();
}

Stresstestergebnis

Node.js App Stresstestergebnis

Update: Auf Vorschlag von Gorgi Kosev

npm install -g recluster-cli && NODE_ENV=production recluster-cli app.js 8 verwenden

nodejs test 2

Stresstestergebnis der ASP.NET Core App

asp.net core stress test result

Kann meinen Augen nicht trauen! Es kann nicht wahr sein, dass asp.net core in diesem Basistest viel schneller ist als nodejs. Natürlich ist dies nicht die einzige Metrik, die verwendet wird, um die Leistung zwischen diesen beiden Webtechnologien zu messen, aber ich frage mich , was ich auf der node.js-Seite falsch mache? .

Als professioneller asp.net-Entwickler und der Wunsch, node.js in persönlichen Projekten zu adaptieren, schreckt mich dies ab - da ich ein bisschen paranoid in Bezug auf die Leistung bin. Ich dachte, node.js ist schneller als asp.net core (im Allgemeinen - wie in verschiedenen anderen Benchmarks zu sehen), ich möchte es mir nur beweisen (um mich bei der Anpassung von node.js zu ermutigen).

Bitte antworten Sie im Kommentar, wenn Sie möchten, dass ich weitere Code-Schnipsel einbinde.

Update: Zeitverteilung der .NET Core App

aspnetcore app time distribution

Serverantwort

HTTP/1.1 200 OK
Cache-Control: no-store,no-cache
Date: Fri, 12 May 2017 07:46:56 GMT
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Server: Kestrel
155
undefined

Wie viele andere angedeutet haben, fehlt dem Vergleich der Kontext.
Zum Zeitpunkt der Veröffentlichung war der asynchrone Ansatz von node.js revolutionär. Seitdem haben andere Sprachen und Web-Frameworks die Ansätze übernommen, die sie zum Mainstream gemacht haben.

Um zu verstehen, was der Unterschied bedeutete, müssen Sie eine Blockierungsanforderung simulieren, die eine gewisse IO Arbeitslast darstellt, z. B. eine Datenbankanforderung. In einem Thread-pro-Anfrage-System erschöpft dies den Thread-Pool und neue Anfragen werden in eine Warteschlange gestellt, die auf einen verfügbaren Thread wartet.
Bei nicht blockierenden io-Frameworks ist dies nicht der Fall.

Betrachten Sie diesen node.js-Server, der 1 Sekunde wartet, bevor er antwortet

const server = http.createServer((req, res) => {
  setTimeout(() => {
    res.statusCode = 200;
    res.end();
  }, 1000);
});

Lassen Sie uns nun 10s lang 100 gleichzeitige Verbindungen darauf werfen. Wir rechnen daher mit etwa 1000 auszuführenden Anfragen.

$ wrk -t100 -c100 -d10s http://localhost:8000
Running 10s test @ http://localhost:8000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.01s    10.14ms   1.16s    99.57%
    Req/Sec     0.13      0.34     1.00     86.77%
  922 requests in 10.09s, 89.14KB read
Requests/sec:     91.34
Transfer/sec:      8.83KB

Wie Sie sehen, kommen wir mit 922 fertig in den Ballpark.

Betrachten Sie nun den folgenden asp.net-Code, der so geschrieben wurde, als ob async/await noch nicht unterstützt wurde.

app.Run((context) =>
{
    Thread.Sleep(1000);
    context.Response.StatusCode = 200;
    return Task.CompletedTask;
});

$ wrk -t100 -c100 -d10s http://localhost:5000
Running 10s test @ http://localhost:5000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.08s    74.62ms   1.15s   100.00%
    Req/Sec     0.00      0.00     0.00    100.00%
  62 requests in 10.07s, 5.57KB read
  Socket errors: connect 0, read 0, write 0, timeout 54
Requests/sec:      6.16
Transfer/sec:     566.51B

62! Hier sehen wir die Grenze des Threadpools. Durch die Optimierung könnten mehr gleichzeitige Anforderungen ausgeführt werden, jedoch auf Kosten von mehr Serverressourcen.

Bei diesen E/A-gebundenen Workloads war der Versuch, das Blockieren der Verarbeitungsthreads zu vermeiden, so dramatisch.

Lassen Sie es uns jetzt auf den heutigen Tag bringen, an dem dieser Einfluss die Branche erfasst hat, und Dotnet die Möglichkeit geben, seine Verbesserungen zu nutzen.

app.Run(async (context) =>
{
    await Task.Delay(1000);
    context.Response.StatusCode = 200;
});

$ wrk -t100 -c100 -d10s http://localhost:5000
Running 10s test @ http://localhost:5000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.01s    19.84ms   1.16s    98.26%
    Req/Sec     0.12      0.32     1.00     88.06%
  921 requests in 10.09s, 82.75KB read
Requests/sec:     91.28
Transfer/sec:      8.20KB

Keine Überraschungen hier, wir passen jetzt zu node.js.

Was bedeutet das alles?

Ihre Eindrücke, dass node.js das "schnellste" ist, stammen aus einer Ära, in der wir nicht mehr leben. Hinzu kommt, dass niemals node/js/v8 "schnell" war, sondern dass sie den Thread pro Anfrage unterbrochen haben Modell. Alle anderen haben aufgeholt.

Wenn Ihr Ziel die schnellstmögliche Bearbeitung einzelner Anfragen ist, schauen Sie sich die seriösen Benchmarks an, anstatt Ihre eigenen zu würfeln. Aber wenn Sie stattdessen einfach etwas wollen, das sich nach modernen Maßstäben skalieren lässt, wählen Sie die Sprache, die Sie mögen, und stellen Sie sicher, dass Sie diese Threads nicht blockieren.

Haftungsausschluss: An einem verschlafenen Sonntagmorgen wird der gesamte Code auf einem veralteten MacBook Air geschrieben und getestet. Gerne können Sie den Code herunterladen und ihn unter Windows ausprobieren oder an Ihre Bedürfnisse anpassen - https://github.com/csainty/nodejs-vs-aspnetcore

167
Chris Sainty

Knoten-Frameworks wie Express und Koa haben einen schrecklichen Overhead. "Raw" Node ist deutlich schneller.

Ich habe es nicht ausprobiert, aber es gibt ein neueres Framework, das der Leistung von "Raw" Node sehr nahe kommt: https://github.com/aerojs/aero

(siehe Benchmark auf dieser Seite)

update: Hier einige Zahlen: https://github.com/blitzprog/webserver-benchmarks

Node:
    31336.78
    31940.29
Aero:
    29922.20
    27738.14
Restify:
    19403.99
    19744.61
Express:
    19020.79
    18937.67
Koa:
    16182.02
    16631.97
Koala:
    5806.04
    6111.47
Hapi:
    497.56
    500.00

Wie Sie sehen können, sind die Overheads in den beliebtesten node.js-Frameworks SEHR bedeutend!

11
smorgs