Risultato imprevisto di node.js vs ASP.NET Core performance test


177

Sto facendo un rapido stress test su due (ciao) ciao progetti mondiali scritti in e . Entrambi sono in esecuzione in modalità di produzione e senza un logger collegato ad essi. Il risultato è sorprendente! Il core ASP.NET sta superando le prestazioni dell'app node.js anche dopo aver fatto del lavoro extra mentre l'app node.js sta solo eseguendo il rendering di una vista.

App 1: http://localhost:3000/nodejs node.js

Utilizzando : node.js, motore di rendering espresso e vash.

app nodejs

Il codice in questo endpoint è

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

Come puoi vedere, non fa nulla a parte l'invio della data corrente tramite la timevariabile alla vista.

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

Utilizzando : ASP.NET Core, targeting modello predefinitodnxcore50

Tuttavia questa app fa qualcosa di diverso dal semplice rendering di una pagina con una data su di essa. Genera 5 paragrafi di vari testi casuali. Questo dovrebbe teoricamente rendere questo un po 'più pesante dell'app nodejs.

app core asp.net

Ecco il metodo di azione che rende questa pagina

[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();
}

Risultato del test di stress

Risultato dello stress test dell'app Node.js

Aggiornamento: su suggerimento di Gorgi Kosev

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

test nodejs 2

Risultato del test di stress dell'app ASP.NET Core

risultato del test di stress core asp.net

Non posso credere ai miei occhi! Non può essere vero che in questo test di base asp.net core è molto più veloce di nodejs. Ovviamente questa non è l'unica metrica utilizzata per misurare le prestazioni tra queste due tecnologie Web, ma mi chiedo cosa sto facendo di sbagliato nel lato node.js? .

Essendo uno sviluppatore professionista di asp.net e desiderando adattare node.js in progetti personali, questo è un po 'scoraggiante, dato che sono un po' paranoico riguardo alle prestazioni. Ho pensato che node.js sia più veloce del core asp.net (in generale - come visto in vari altri parametri di riferimento) Voglio solo dimostrarlo a me stesso (per incoraggiarmi ad adattare node.js).

Rispondi in commento se desideri che includa più frammenti di codice.

Aggiornamento: distribuzione del tempo dell'app .NET Core

distribuzione del tempo dell'app aspnetcore

Risposta del server

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

52
"Ho sempre pensato che node.js sia più veloce del core asp.net" - Sono curioso di sapere perché lo pensi? Non ho visto alcun benchmark che supportasse questo (i motivi principali che ho sentito per l'adozione di node.js erano "facilità d'uso" e "tempo di sviluppo / iterazione più veloce")
UnholySheep,

7
@UnholySheep È tutto ciò che ho sentito amico, ho anche sentito che è "facile da usare" e "più veloce da sviluppare", in genere da persone che non hanno mai funzionato in ASP.NET, specialmente in VisualStudio. Non mi sto vantando di alcuna tecnologia, ma questo è il modello che ho notato.
indefinito

3
Qual è la domanda qui? Se è plausibile: sì, lo è. techempower.com/benchmarks/… .... Aggiorna anche la tua toolchain Dnxcore50 è obsoleto da almeno un anno o due.
Thomas,

2
@Tony tramite il modulo cluster NodeJs genera più lavoratori che fanno e condividono il carico del processo principale che è in ascolto su un singolo processo. Evita semplicemente di impostare più applicazioni su porte diverse. Inoltre, se nodeJs è in esecuzione in modalità cluster, dovrebbe esserci lo stesso numero di applicazioni Web Asp.Net in esecuzione su IIS su porte diff e condividere il carico tra loro attraverso un bilanciamento del carico, quindi sarà un confronto corretto.
Vipresh,

36
Node.js è ottimo per molte cose, ma la velocità pura per richiesta non è una di queste. Ciò che eccelle è essere un broker per le operazioni di I / O, a causa della cosa non bloccante del loop degli eventi, che, quando Node era nuovo e brillante, era un grosso problema. Naturalmente, da allora altri linguaggi e framework hanno raggiunto, quindi in .NET abbiamo Task Parallel Library e I / O asincroni e async / waitit. Ciò in cui Node non eccelle sono le operazioni associate alla CPU come il rendering della pagina, perché è JavaScript a thread singolo.
Mark Rendle,

Risposte:


188

Come molti altri hanno accennato, il confronto manca di contesto.
Al momento del rilascio, l'approccio asincrono di node.js era rivoluzionario. Da allora, altre lingue e framework web hanno adottato gli approcci che hanno adottato.

Per comprendere il significato della differenza, è necessario simulare una richiesta di blocco che rappresenti un carico di lavoro di I / O, come una richiesta di database. In un sistema thread-per-request, questo esaurirà il pool di thread e le nuove richieste verranno inserite in una coda in attesa di un thread disponibile.
Con i framework io non bloccanti ciò non accade.

Considera questo server node.js che attende 1 secondo prima di rispondere

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

Ora lanciamo 100 convenzioni simultanee, per 10 secondi. Quindi prevediamo di completare circa 1000 richieste.

$ 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

Come puoi vedere, entriamo nel campo da baseball con 922 completato.

Consideriamo ora il seguente codice asp.net, scritto come se async / await non fosse ancora supportato, quindi risalente all'era del lancio di node.js.

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! Qui vediamo il limite del threadpool. Ottimizzandolo potremmo ottenere più richieste simultanee, ma a costo di più risorse del server.

Per questi carichi di lavoro associati a IO, la mossa per evitare di bloccare i thread di elaborazione è stata così drammatica.

Ora portiamolo a oggi, dove quell'influenza si è diffusa nel settore e permettiamo a dotnet di trarre vantaggio dai suoi miglioramenti.

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

Nessuna sorpresa qui, ora abbiniamo node.js.

Cosa significa tutto ciò?

Le tue impressioni sul fatto che node.js sia il "più veloce" provengono da un'era in cui non viviamo più. Inoltre, il nodo / js / v8 non è mai stato "veloce", è stato che hanno rotto il thread per richiesta modello. Tutti gli altri hanno recuperato.

Se il tuo obiettivo è l'elaborazione più rapida possibile di singole richieste, osserva i parametri di riferimento seri invece di eseguire il rollup delle tue. Ma se invece quello che vuoi è semplicemente qualcosa che si adatta agli standard moderni, scegli la lingua che preferisci e assicurati di non bloccare quei thread.

Dichiarazione di non responsabilità: tutto il codice scritto e i test vengono eseguiti su un MacBook Air obsoleto durante una sonnolenta domenica mattina. Sentiti libero di prendere il codice e provarlo su Windows o modificare le tue esigenze - https://github.com/csainty/nodejs-vs-aspnetcore


35
NodeJs non è mai stato univoco, il modello Thread per richiesta esisteva anche in Asp.Net prima dell'introduzione di nodejs. Tutti i metodi di I / O avevano 2 versioni sincrone e asincrone fornite dal Framework, i loro metodi ASYNC che terminavano con la parola chiave "Async" per per esempio. methodNameAsync
Vipresh,

Ad es. Puoi fare riferimento a questo articolo relativo alle operazioni di DB risalenti al 2008 codedigest.com/Articles/ADO/…
Vipresh

4
"gli approcci che hanno adottato": poche cose sono uniche, mettono il problema di fronte a un pubblico molto più ampio. Avere un approccio disponibile e averlo inserito come principio fondamentale sono due cose molto diverse.
Chris Sainty,

4
La migliore risposta qui. Periodo.
Narvalex,

3
@LeeBrindley Non sono d'accordo, questo non sta provando a dimostrare il massimo throughput dell'hardware dato, sta dimostrando la differenza tra blocco e non blocco. Se desideri confronti di throughput non elaborati, mi collego a techempower.
Chris Sainty,

14

Node Frameworks come Express e Koa hanno un sovraccarico terribile. Il nodo "Raw" è significativamente più veloce.

Non l'ho provato, ma c'è un framework più recente che si avvicina molto alle prestazioni del nodo "Raw": https://github.com/aerojs/aero

(vedi benchmark in quella pagina)

aggiornamento: ecco alcuni dati: 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

Come puoi vedere, le spese generali nei framework node.js più popolari sono MOLTO significative!


5
a cosa servono i numeri? Più alto è meglio?
Iamisti,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.