Resultado inesperado do node.js x teste de desempenho do ASP.NET Core

177

Estou fazendo um teste rápido de estresse em dois (meio) hello world projects escritos em e . Ambos estão sendo executados no modo de produção e sem um criador de logs anexado a eles. O resultado é surpreendente! O núcleo do ASP.NET está superando o aplicativo node.js. mesmo após um trabalho extra, enquanto o aplicativo node.js. está apenas renderizando uma exibição.

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

Usando : node.js, mecanismo de renderização express e vash.

app nodejs

O código neste terminal é

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

Como você pode ver, ele não faz nada além de enviar a data atual através da timevariável para a visualização.

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

Usando : ASP.NET Core, segmentação de modelo padrãodnxcore50

No entanto, este aplicativo faz algo diferente de apenas renderizar uma página com uma data nela. Ele gera 5 parágrafos de vários textos aleatórios. Teoricamente, isso deve tornar isso um pouco mais pesado que o aplicativo nodejs.

aplicativo principal do asp.net

Aqui está o método de ação que renderiza esta página

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

Resultado do teste de estresse

Resultado do teste de estresse do aplicativo Node.js

Atualização: Seguindo sugestão de Gorgi Kosev

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

nodejs test 2

Resultado do teste de estresse do aplicativo ASP.NET Core

resultado do teste de estresse do núcleo do asp.net

Não posso acreditar nos meus olhos! Não é verdade que, neste teste básico, o núcleo do asp.net é muito mais rápido que o nodejs. É claro que essa não é a única métrica usada para medir o desempenho entre essas duas tecnologias da web, mas estou me perguntando o que estou fazendo de errado no lado do node.js. .

Sendo um desenvolvedor profissional do asp.net e desejando adaptar o node.js em projetos pessoais, isso me deixa de lado - já que estou um pouco paranóico com relação ao desempenho. Eu pensei que o node.js é mais rápido que o núcleo do asp.net (em geral - como visto em vários outros benchmarks) - só quero provar isso para mim mesmo (para me encorajar a adaptar o node.js.).

Por favor, responda no comentário se você quiser que eu inclua mais trechos de código.

Atualização: distribuição de tempo do aplicativo .NET Core

distribuição de tempo do aplicativo aspnetcore

Resposta do servidor

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
Indefinido
fonte
52
"Eu sempre pensei que o node.js é mais rápido que o núcleo do asp.net" - estou curioso por que você acha isso? Eu não vi qualquer referência que apoiaria isso (as principais razões que eu ouvi para a adopção node.js eram "facilidade de uso" e "desenvolvimento / iteração tempo mais rápido")
UnholySheep
7
@UnholySheep Foi tudo o que ouvi amigo, também ouvi dizer que é "fácil de usar" e "mais rápido de desenvolver" também, geralmente de pessoas que nunca trabalharam no ASP.NET, principalmente no VisualStudio. Não estou me gabando de nenhuma tecnologia - mas esse é o padrão que notei.
indefinido
3
Qual é a pergunta aqui? Se é plausível: Sim, é. techempower.com/benchmarks/… .... Atualize também o seu conjunto de ferramentas O Dnxcore50 está desatualizado por pelo menos um ano ou dois.
Thomas
2
O @Tony usando o módulo de cluster NodeJs gera vários trabalhadores fazendo e compartilhando a carga do processo principal que está ouvindo no processo único. Evita apenas a necessidade de configurar vários aplicativos em portas diferentes. Além disso, se o nodeJs estiver em execução no modo de cluster, deverá haver o mesmo número de aplicativos Web do Asp.Net em execução no IIS em portas diff e compartilhar a carga entre eles por meio de algum balanceador de carga, então será a comparação correta.
Vipresh
36
O Node.js é ótimo para muitas coisas, mas a velocidade bruta por solicitação não é uma delas. O que se destaca é ser um intermediário para operações de E / S, por causa do loop de eventos sem bloqueio, que, quando o Node era novo e brilhante, era um grande negócio. É claro que, desde então, outras linguagens e estruturas alcançaram, portanto, no .NET, temos a Biblioteca Paralela de Tarefas e E / S assíncrona e async / waiting. O que o Nó não se destaca é nas operações ligadas à CPU, como a renderização de página, porque é JavaScript de thread único.
precisa

Respostas:

188

Como muitos outros aludiram, a comparação carece de contexto.
No momento do seu lançamento, a abordagem assíncrona do node.js era revolucionária. Desde então, outras linguagens e estruturas da web adotam as abordagens adotadas na corrente principal.

Para entender o significado da diferença, você precisa simular uma solicitação de bloqueio que represente alguma carga de trabalho de E / S, como uma solicitação de banco de dados. Em um sistema de encadeamento por solicitação, isso esgotará o conjunto de encadeamentos e novas solicitações serão colocadas em uma fila aguardando um encadeamento disponível.
Com estruturas sem bloqueio de io, isso não acontece.

Considere este servidor node.js que espera 1 segundo antes de responder

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

Agora vamos lançar 100 conencções simultâneas, por 10s. Portanto, esperamos que cerca de 1.000 solicitações sejam concluídas.

$ 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

Como você pode ver, entramos no estádio com 922 concluídos.

Agora, considere o seguinte código asp.net, escrito como se async / waitit ainda não fosse suportado, portanto, remonta à época de lançamento do 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! Aqui vemos o limite do pool de threads. Ao ajustá-lo, podemos obter mais solicitações simultâneas, mas à custa de mais recursos do servidor.

Para essas cargas de trabalho ligadas à E / S, a ação para evitar o bloqueio dos encadeamentos de processamento foi tão dramática.

Agora, vamos trazê-lo para hoje, onde essa influência se espalhou pelo setor e permitir que a dotnet aproveite suas melhorias.

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

Sem surpresas aqui, agora combinamos o node.js.

Então, o que tudo isso significa?

Suas impressões de que o node.js é o "mais rápido" vêm de uma época em que não vivemos mais. Acrescente a isso que nunca foi o nó / js / v8 que foi "rápido", mas que eles quebraram o encadeamento por solicitação modelo. Todo mundo está se atualizando.

Se o seu objetivo é o processamento mais rápido possível de solicitações únicas, observe os benchmarks sérios em vez de criar os seus próprios. Mas se o que você deseja é simplesmente algo que se adapta aos padrões modernos, escolha o idioma que você gosta e verifique se não está bloqueando esses tópicos.

Isenção de responsabilidade: Todo o código escrito e os testes são executados em um MacBook Air antigo durante uma sonolenta manhã de domingo. Sinta-se à vontade para pegar o código e testá-lo no Windows ou ajustar suas necessidades - https://github.com/csainty/nodejs-vs-aspnetcore

Chris Sainty
fonte
35
NodeJs nunca foi exclusivo, o modelo Thread por solicitação também existia no Asp.Net antes da introdução do nodejs. Todos os métodos que executavam a E / S tinham 2 versões síncronas e assíncronas fornecidas pelo Framework, seus métodos ASYNC terminando com a palavra-chave "Async" para por exemplo. methodNameAsync
Vipresh
Como um exemplo. Você pode consultar este artigo relacionado às operações de banco de dados que datam de 2008 codedigest.com/Articles/ADO/…
Vipresh
4
"as abordagens adotadas pela maioria" - poucas coisas são únicas, colocam a questão na frente de um público muito maior. Ter uma abordagem disponível e tê-la como princípio básico são duas coisas muito diferentes.
precisa
4
A melhor resposta aqui. Período.
Narvalex 07/07
3
@LeeBrindley Não concordo, isso não está tentando demonstrar o rendimento máximo do hardware fornecido, está demonstrando a diferença entre bloqueio e não-bloqueio. Se você quiser comparações de taxa de transferência bruta, vinculo ao techempower.
precisa
14

Estruturas de nós como Express e Koa têm uma sobrecarga terrível. O nó "Raw" é significativamente mais rápido.

Eu não tentei, mas há uma estrutura mais nova que se aproxima muito do desempenho do nó "Raw": https://github.com/aerojs/aero

(veja benchmark nessa página)

update: Aqui estão algumas figuras: 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

Como você pode ver, as despesas gerais nas estruturas node.js mais populares são MUITO significativas!

smorgs
fonte
5
para que servem os números? Quanto maior, melhor?
Iamisti