Unerwartetes Ergebnis des Leistungstests von node.js vs ASP.NET Core

177

Ich mache einen kurzen Stresstest für zwei (irgendwie) Hallo-Welt-Projekte, in denen geschrieben wurde und . Beide werden im Produktionsmodus und ohne angeschlossenen Logger ausgeführt. Das Ergebnis ist erstaunlich! Der ASP.NET-Kern übertrifft die App node.js auch nach einigen zusätzlichen Arbeiten, während die App node.js nur eine Ansicht rendert.

App 1: http://localhost:3000/nodejs node.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 timeVariable an die Ansicht zu senden .

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

Verwenden von : ASP.NET Core, Standardvorlagen-Targetingdnxcore50

Diese App macht jedoch etwas anderes als nur das Rendern einer Seite mit einem Datum darauf. Es werden 5 Absätze verschiedener zufälliger Texte generiert. Dies sollte theoretisch etwas schwerer machen als die NodeJS-App.

asp.net Kern-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

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

nodejs test 2

Stresstestergebnis der ASP.NET Core App

asp.net Kernstresstestergebnis

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

Als professioneller asp.net-Entwickler und der Wunsch, node.js in persönlichen Projekten anzupassen, schreckt mich das irgendwie ab - da ich ein wenig paranoid in Bezug auf 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 nur mir selbst beweisen (um mich bei der Anpassung von node.js zu ermutigen).

Bitte antworten Sie in einem Kommentar, wenn ich weitere Codefragmente hinzufügen soll.

Update: Zeitverteilung der .NET Core App

Aspnetcore App Zeitverteilung

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
nicht definiert
quelle
51
"Ich dachte immer, node.js ist schneller als asp.net core" - ich bin gespannt, warum du das denkst? Ich habe keine Benchmarks gesehen, die dies unterstützen würden (die Hauptgründe für die Einführung von node.js waren "Benutzerfreundlichkeit" und "schnellere Entwicklungs- / Iterationszeit")
UnholySheep
7
@UnholySheep Es ist alles, was ich gehört habe, Kumpel, ich habe auch gehört, dass es "einfach zu bedienen" und "schneller zu entwickeln" ist, im Allgemeinen von Leuten, die nie in ASP.NET gearbeitet haben, insbesondere in VisualStudio. Ich prahle nicht mit irgendeiner Technologie - aber das ist das Muster, das mir aufgefallen ist.
undefiniert
3
Was ist die Frage hier? Wenn es plausibel ist: Ja, das ist es. techempower.com/benchmarks/… .... Aktualisieren Sie auch Ihre Toolchain Dnxcore50 ist seit mindestens ein oder zwei Jahren veraltet.
Thomas
2
@Tony mit dem Cluster-Modul NodeJs erzeugt mehrere Worker, die die Last des Hauptprozesses teilen, der einen einzelnen Prozess abhört. Es wird lediglich vermieden, dass mehrere Anwendungen an verschiedenen Ports eingerichtet werden müssen. Auch wenn nodeJs im Cluster-Modus ausgeführt wird, sollte die gleiche Anzahl von Asp.Net-Webanwendungen in IIS auf verschiedenen Ports ausgeführt werden und die Last zwischen ihnen über einen Load Balancer aufgeteilt werden. Dies ist ein richtiger Vergleich.
Vipresh
36
Node.js eignet sich hervorragend für viele Dinge, aber die Geschwindigkeit pro Anfrage gehört nicht dazu. Was es auszeichnet, ist ein Broker für E / A-Operationen zu sein, aufgrund der nicht blockierenden Event-Loop-Sache, die, als Node neu und glänzend war, eine große Sache war. Natürlich haben seitdem andere Sprachen und Frameworks aufgeholt, sodass wir in .NET die Task Parallel Library und asynchrone E / A und async / await haben. Was Node nicht auszeichnet, sind CPU-gebundene Operationen wie das Rendern von Seiten, da es sich um Single-Threaded-JavaScript handelt.
Mark Rendle

Antworten:

187

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 Mainstream-Ansätze übernommen.

Um zu verstehen, was der Unterschied bedeutet, müssen Sie eine Blockierungsanforderung simulieren, die eine E / A-Arbeitslast darstellt, z. B. eine Datenbankanforderung. In einem Thread-per-Request-System wird dadurch der Threadpool erschöpft und neue Anforderungen 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 10 Sekunden lang 100 gleichzeitige Verbindungen darauf werfen. Wir erwarten also, dass ungefähr 1000 Anfragen abgeschlossen werden.

$ 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 können, kommen wir mit 922 fertig in den Baseballstadion.

Betrachten Sie nun den folgenden asp.net-Code, der so geschrieben wurde, als ob async / await noch nicht unterstützt wurde, und datiert uns daher auf die Start-Ära von node.j zurück.

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 auftreten, jedoch auf Kosten von mehr Serverressourcen.

Für diese E / A-gebundenen Workloads war der Schritt, das Blockieren der Verarbeitungsthreads zu vermeiden, so dramatisch.

Lassen Sie es uns auf den heutigen Tag bringen, an dem dieser Einfluss die Branche erfasst hat und Dotnet die Möglichkeit bietet, 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 stimmen jetzt mit node.js überein.

Was bedeutet das alles?

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

Wenn Ihr Ziel die schnellstmögliche Bearbeitung einzelner Anfragen ist, sollten Sie sich die seriösen Benchmarks ansehen, anstatt Ihre eigenen zu rollen. Aber wenn Sie stattdessen einfach etwas wollen, das sich an moderne Standards anpasst, wählen Sie eine beliebige Sprache und stellen Sie sicher, dass Sie diese Threads nicht blockieren.

Haftungsausschluss: Der gesamte Code, der an einem verschlafenen Sonntagmorgen auf einem alternden MacBook Air geschrieben und getestet wird. Nehmen Sie den Code und probieren Sie ihn unter Windows aus oder passen Sie ihn an Ihre Bedürfnisse an - https://github.com/csainty/nodejs-vs-aspnetcore

Chris Sainty
quelle
34
NodeJs war nie eindeutig, das Thread-per-Request-Modell war auch in Asp.Net vorhanden, bevor nodejs eingeführt wurde. Alle E / A-Methoden hatten zwei vom Framework bereitgestellte synchrone und asynchrone Versionen, deren ASYNC-Methoden mit dem Schlüsselwort "Async" für endeten z.B. methodNameAsync
Vipresh
Als z. Sie können auf diesen Artikel verweisen, der sich auf DB-Operationen aus dem Jahr 2008 bezieht. Codedigest.com/Articles/ADO/…
Vipresh
4
"Die Ansätze, die sie im Mainstream gewählt haben" - wenige Dinge sind einzigartig, sie stellen das Thema einem viel breiteren Publikum vor. Einen Ansatz zur Verfügung zu haben und ihn als Kernprinzip einzubringen, sind zwei sehr unterschiedliche Dinge.
Chris Sainty
4
Die beste Antwort hier. Zeitraum.
Narvalex
3
@ LeeBrindley Ich bin anderer Meinung, dies versucht nicht, den maximalen Durchsatz der angegebenen Hardware zu demonstrieren, sondern zeigt den Unterschied zwischen Blockieren und Nicht-Blockieren. Wenn Sie Rohdurchsatzvergleiche wünschen, verweise ich auf techempower.
Chris Sainty
14

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

Ich habe es nicht ausprobiert, aber es gibt ein neueres Framework, das der Leistung des "Raw" -Knotens 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 Frameworks von node.j SEHR bedeutend!

Smorgs
quelle
5
Wofür sind die Zahlen? Je höher desto besser?
Iamisti