Desempenho do Node.js vs .Net


183

Eu li muito sobre o Node.js ser rápido e capaz de acomodar grandes quantidades de carga. Alguém tem alguma evidência do mundo real disso versus outros frameworks, particularmente o .Net? A maioria dos artigos que li são anedóticos ou não têm comparações com o .Net.

obrigado


1
Você poderia ser mais preciso em que tipo de cenário estamos falando?
Marcus Granström

1
Estou interessado em qualquer comparação de desempenho de .Net e Node.js para aplicativos Web comparáveis ​​em execução no IIS.
David Merrilees

1
Não consigo imaginar alguém construindo um site com alto desempenho. requisitos do .Net. O problema mais básico com o qual você se depara é que não será muito rentável em termos de licenciamento, já que possui alto desempenho. sites geralmente exigem expansão. E não, eu não sou um odiador de .Net. .Net paga as contas.
Shane Courtrille

4
Eu tive que fazer testes internos de uma pequena API REST usando Node / express / mongo e o novo .net webapi / mongo e houve diferenças de desempenho com base no que o cliente queria, mas no final do dia, não o suficiente para criar uma diferença. Você precisa desenvolver seus próprios testes com base em seus próprios cenários. Demoramos três dias para escrever as diferentes APIs nos dois idiomas e mais alguns dias para configurar corretamente os testes. Se você planeja fazer algo remotamente sério, sugiro configurar testes com base em seus requisitos e decidir por si mesmo qual é o melhor para sua carga.
AlexGad

5
@ShaneCourtrille Você está confundindo .Net (uma estrutura) e Windows (um sistema operacional). São coisas muito diferentes e NÃO há requisitos de licenciamento para .Net (que roda muito bem no Linux como Mono).
rainabba

Respostas:


366

Ser RÁPIDO e lidar com muita carga são duas coisas diferentes. Um servidor que é realmente RÁPIDO ao atender uma solicitação por segundo pode coaxar totalmente se você enviar 500 solicitações por segundo (em LOAD ).

Você também deve considerar páginas estáticas (e armazenadas em cache) versus páginas dinâmicas. Se você estiver preocupado com páginas estáticas, o IIS provavelmente vencerá o nó porque o IIS usa o cache no modo kernel, o que significa que as solicitações que solicitam uma página estática nem saem do kernel.

Suponho que você esteja procurando uma comparação entre o ASP.NET e o nó. Nesta batalha, depois que tudo tiver sido compilado / interpretado, você provavelmente terá um desempenho muito próximo. Talvez o .NET seja um pouco MAIS RÁPIDO ou talvez o nó seja um pouco MAIS RÁPIDO , mas provavelmente está perto o suficiente para você não se importar. Eu apostaria no .NET, mas não tenho certeza.

O local em que o nó é realmente atraente é para lidar com LOAD . É aqui que as tecnologias realmente diferem. O ASP.NET dedica um encadeamento para cada solicitação do seu pool de encadeamentos e, uma vez esgotado o ASP.NET, todas as solicitações de encadeamentos disponíveis começam a ficar na fila. Se você estiver exibindo aplicativos "Hello World", como o exemplo de @shankar, isso pode não importar muito, porque os threads não serão bloqueados e você poderá lidar com muitas solicitações antes de você ficar sem threads. O problema com o modelo ASP.NET ocorre quando você começa a fazer solicitações de E / S que bloqueiam o encadeamento (chame um banco de dados, faça uma solicitação http para um serviço, leia um arquivo do disco). Essas solicitações de bloqueio significam que seu thread valioso do pool de threads não está fazendo nada. Quanto mais bloqueio você tiver,CARREGAR seu aplicativo ASP.NET poderá veicular.

Para evitar esse bloqueio, use as portas de conclusão de E / S que não exigem retenção de um encadeamento enquanto você espera por uma resposta. O ASP.NET suporta isso, mas infelizmente muitas das estruturas / bibliotecas comuns no .NET NÃO. Por exemplo, o ADO.NET suporta portas de conclusão de E / S, mas o Entity Framework não as utiliza. Portanto, você pode criar um aplicativo ASP.NET que seja puramente assíncrono e lide com muita carga, mas a maioria das pessoas não, porque não é tão fácil quanto criar um que seja síncrono e talvez você não consiga usar algumas de suas partes favoritas da estrutura (como linq para entidades) se você o fizer.

O problema é que o ASP.NET (e o .NET Framework) foi criado para não opinar sobre E / S assíncrona. O .NET não se importa se você escreve código síncrono ou assíncrono; portanto, cabe ao desenvolvedor tomar essa decisão. Parte disso ocorre porque o threading e a programação com operações assíncronas eram considerados "difíceis", e o .NET queria fazer todo mundo feliz (noobs e especialistas). Ficou ainda mais difícil porque o .NET acabou com 3-4 padrões diferentes para executar assíncrona. O .NET 4.5 está tentando voltar e adaptar a estrutura .NET para ter um modelo opinativo em torno da E / S assíncrona, mas pode demorar um pouco até que as estruturas de que você se preocupe realmente a suportem.

Os projetistas do nó, por outro lado, fizeram uma escolha opinativa de que TODAS as E / S deveriam ser assíncronas. Por causa dessa decisão, os designers do nó também foram capazes de decidir que cada instância do nó seria encadeada única para minimizar a troca de encadeamentos e que um encadeamento executaria apenas o código que estava na fila. Pode ser uma nova solicitação, pode ser o retorno de chamada de um pedido de banco de dados, pode ser o retorno de chamada de uma solicitação de descanso http que você fez. O nó tenta maximizar a eficiência da CPU, eliminando as opções de contexto do encadeamento. Como o nó fez essa escolha opinativa de que TODAS as E / S são assíncronas, isso também significa que todas as suas estruturas / complementos suportam essa opção. É mais fácil escrever aplicativos 100% assíncronos no nó (porque o nó obriga a gravar aplicativos assíncronos).

Novamente, não tenho números concretos para provar de uma maneira ou de outra, mas acho que o nó venceria a competição LOAD pelo aplicativo da Web típico. Um aplicativo .NET altamente otimizado (100% assíncrono) pode dar ao aplicativo node.js equivalente uma corrida por seu dinheiro, mas se você fizer uma média de todos os aplicativos .NET e de todos os aplicativos existentes, provavelmente o nó provavelmente lidará com mais CARGA.

Espero que ajude.


39
Lembre-se de que o ASP.NET suporta manipuladores de solicitação assíncrona há muito tempo e, com o MVC4, eles se tornaram extremamente simples de usar.
Fab123 #

12
"Essas solicitações de bloqueio significam que seu encadeamento valioso do pool de encadeamentos não está fazendo nada. Quanto mais bloqueios você tiver, menos LOAD seu aplicativo ASP.NET poderá atender." Por que importa se estamos na fila de espera (a solicitação recebida) ou no back-end (o encadeamento de trabalho real)? Não importa o quê, a solicitação do cliente está aguardando a resposta. Eu acho que a chave que as pessoas ignoram neste debate é "Throughput". Não se trata de quantas conexões simultâneas um servidor mantém, é a rapidez com que ele pode responder a cada solicitação, certo?
sjdirect

19
// Não me permite editar meu comentário, então aqui está o que eu quis dizer.// @sjdirect - O rendimento não é o mesmo que o tempo de resposta. Você está certo em se preocupar com o tempo de resposta, mas é uma escolha entre tempo de fila + tempo de resposta ou apenas tempo de resposta. O processamento da solicitação demorará tanto tempo nos dois cenários (a execução de forma síncrona NÃO fará com que sua solicitação de banco de dados seja mais rápida), mas se os encadeamentos da solicitação estiverem bloqueados, você também adicionará tempo de fila às solicitações porque você não pode nem começar a processar a solicitação até que as solicitações anteriores sejam concluídas.
Matt Dotson

6
Isso foi realmente informativo, obrigado! Uma coisa a se notar é que o Entity Framework 6 (atualmente RC1) agora suporta o padrão assíncrono do .NET 4.5. msdn.microsoft.com/en-us/data/jj819165
parliament

4
Isso é extremamente especulativo! Seria ótimo ter dados. Geralmente é assim que decido como proceder com tópicos de desempenho.
22615 KingPuppy #

50

Fiz um teste de desempenho rudimentar entre o nodejs e o IIS. O IIS é cerca de 2,5 vezes mais rápido que o nodejs ao exibir "olá, mundo!". código abaixo.

meu hardware: Dell Latitude E6510, Core i5 (núcleo duplo), 8 GB de RAM, sistema operacional Windows 7 Enterprise de 64 bits

servidor de nó

runs at http://localhost:9090/
/// <reference path="node-vsdoc.js" />
var http = require("http");
http.createServer(function (request, response) {
response.writeHead(200, { "Content-Type": "text/html" });
response.write("<p>hello, world!</p>");
response.end();
}).listen(9090);

default.htm

hosted by iis at http://localhost/test/
<p>hello, world!</p>

meu próprio programa de benchmark usando a biblioteca paralela de tarefas:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace HttpBench
{
class Program
{
    private int TotalCount = 100000;
    private int ConcurrentThreads = 1000;
    private int failedCount;
    private int totalBytes;
    private int totalTime;
    private int completedCount;
    private static object lockObj = new object();

    /// <summary>
    /// main entry point
    /// </summary>
    static void Main(string[] args)
    {
        Program p = new Program();
        p.Run(args);
    }

    /// <summary>
    /// actual execution
    /// </summary>
    private void Run(string[] args)
    {
        // check command line
        if (args.Length == 0)
        {
            this.PrintUsage();
            return;
        }
        if (args[0] == "/?" || args[0] == "/h")
        {
            this.PrintUsage();
            return;
        }

        // use parallel library, download data
        ParallelOptions options = new ParallelOptions();
        options.MaxDegreeOfParallelism = this.ConcurrentThreads;
        int start = Environment.TickCount;
        Parallel.For(0, this.TotalCount, options, i =>
            {
                this.DownloadUrl(i, args[0]);
            }
        );
        int end = Environment.TickCount;

        // print results
        this.Print("Total requests sent: {0}", true, this.TotalCount);
        this.Print("Concurrent threads: {0}", true, this.ConcurrentThreads);
        this.Print("Total completed requests: {0}", true, this.completedCount);
        this.Print("Failed requests: {0}", true, this.failedCount);
        this.Print("Sum total of thread times (seconds): {0}", true, this.totalTime / 1000);
        this.Print("Total time taken by this program (seconds): {0}", true, (end - start) / 1000);
        this.Print("Total bytes: {0}", true, this.totalBytes);
    }

    /// <summary>
    /// download data from the given url
    /// </summary>
    private void DownloadUrl(int index, string url)
    {
        using (WebClient client = new WebClient())
        {
            try
            {
                int start = Environment.TickCount;
                byte[] data = client.DownloadData(url);
                int end = Environment.TickCount;
                lock (lockObj)
                {
                    this.totalTime = this.totalTime + (end - start);
                    if (data != null)
                    {
                        this.totalBytes = this.totalBytes + data.Length;
                    }
                }
            }
            catch
            {
                lock (lockObj) { this.failedCount++; }
            }
            lock (lockObj)
            {
                this.completedCount++;
                if (this.completedCount % 10000 == 0)
                {
                    this.Print("Completed {0} requests.", true, this.completedCount);
                }
            }
        }
    }

    /// <summary>
    /// print usage of this program
    /// </summary>
    private void PrintUsage()
    {
        this.Print("usage: httpbench [options] <url>");
    }

    /// <summary>
    /// print exception message to console
    /// </summary>
    private void PrintError(string msg, Exception ex = null, params object[] args)
    {
        StringBuilder sb = new System.Text.StringBuilder();
        sb.Append("Error: ");
        sb.AppendFormat(msg, args);
        if (ex != null)
        {
            sb.Append("Exception: ");
            sb.Append(ex.Message);
        }
        this.Print(sb.ToString());
    }

    /// <summary>
    /// print to console
    /// </summary>
    private void Print(string msg, bool isLine = true, params object[] args)
    {
        if (isLine)
        {
            Console.WriteLine(msg, args);
        }
        else
        {
            Console.Write(msg, args);
        }
    }

}
}

e resultados:

IIS: httpbench.exe http://localhost/test

Completed 10000 requests.
Completed 20000 requests.
Completed 30000 requests.
Completed 40000 requests.
Completed 50000 requests.
Completed 60000 requests.
Completed 70000 requests.
Completed 80000 requests.
Completed 90000 requests.
Completed 100000 requests.
Total requests sent: 100000
Concurrent threads: 1000
Total completed requests: 100000
Failed requests: 0
Sum total of thread times (seconds): 97
Total time taken by this program (seconds): 16
Total bytes: 2000000

nodejs: httpbench.exe http://localhost:9090/

Completed 10000 requests.
Completed 20000 requests.
Completed 30000 requests.
Completed 40000 requests.
Completed 50000 requests.
Completed 60000 requests.
Completed 70000 requests.
Completed 80000 requests.
Completed 90000 requests.
Completed 100000 requests.
Total requests sent: 100000
Concurrent threads: 1000
Total completed requests: 100000
Failed requests: 0
Sum total of thread times (seconds): 234
Total time taken by this program (seconds): 27
Total bytes: 2000000

conclusão: o IIS é mais rápido que o nodejs em cerca de 2,5 vezes (no Windows). Este é um teste muito rudimentar e de forma alguma conclusivo. Mas acredito que este é um bom ponto de partida. O Nodejs provavelmente é mais rápido em outros servidores Web, em outras plataformas, mas no Windows o IIS é o vencedor. Os desenvolvedores que desejam converter seu ASP.NET MVC em nodejs devem fazer uma pausa e pensar duas vezes antes de continuar.

Atualizado (17/5/2012) O Tomcat (no Windows) parece derrotar o IIS, cerca de três vezes mais rápido que o IIS na distribuição de html estático.

tomcat

index.html at http://localhost:8080/test/
<p>hello, world!</p>

resultados tomcat

httpbench.exe http://localhost:8080/test/
Completed 10000 requests.
Completed 20000 requests.
Completed 30000 requests.
Completed 40000 requests.
Completed 50000 requests.
Completed 60000 requests.
Completed 70000 requests.
Completed 80000 requests.
Completed 90000 requests.
Completed 100000 requests.
Total requests sent: 100000
Concurrent threads: 1000
Total completed requests: 100000
Failed requests: 0
Sum total of thread times (seconds): 31
Total time taken by this program (seconds): 5
Total bytes: 2000000

conclusão atualizada: executei o programa de benchmark várias vezes. O Tomcat parece ser o servidor mais rápido na distribuição de HTML ESTÁTICO, NO WINDOWS.

Atualizado (18/5/2012) Anteriormente, eu tinha 100.000 solicitações no total com 10.000 solicitações simultâneas. Aumentei para 1.000.000 de solicitações totais e 100.000 solicitações simultâneas. O IIS aparece como o vencedor, com os Nodejs sendo os piores. Eu tabulei os resultados abaixo:

NodeJS x IIS x Tomcat servindo HTML ESTÁTICO no WINDOWS.


56
Você está comparando maçãs com gatos. Compare o Node.js com o ASP.NET MVC. No máximo, o IIS é mais rápido em servir arquivos estáticos, embora eu duvide muito disso.
Alessioalex 17/05/12

12
@alessioalex: eu não entendo por que essa comparação não é válida. Estou comparando os tempos de resposta para html estático. O IIS está distribuindo html estático no default.htm, enquanto o servidor nodejs está distribuindo a mesma string e o IIS sai à frente. Comparar um aplicativo ASP.NET MVC exigiria mais esforço e tempo, e pretendo fazê-lo mais tarde.
Shankar 17/05

28
Ok, diga que o IIS é melhor para servir arquivos estáticos no Windows do que no Node. O IIS serve apenas arquivos estáticos e, como (Apache ou NGINX), o Node faz muito mais que isso. Você deve comparar o ASP.NET MVC com o Nó (consultar o banco de dados, recuperar dados de um serviço externo, etc etc). Você verá enormes ganhos de desempenho com o Node over ASP.NET MVC.
Alessioalex 18/05

27
Se você fizer isso, pelo menos entenda a natureza do nó. O processo de um nó pode usar apenas um único núcleo. Portanto, o que você está comparando é um processo de nó em execução em um núcleo para um processo do IIS e tomcat usando vários núcleos. Para comparar adequadamente, você precisa executar o nó em cluster. Consulte nodejs.org/api/cluster.html para obter uma solução de cluster simples de usar. No entanto, posso dizer por experiência própria que a diferença entre o nó e o c # assíncrono é de 10 a 15%, de qualquer maneira, dependendo do que você está fazendo.
AlexGad

14
Além disso, o teste de arquivos estáticos com nó e IIS e Tomcat não faz sentido. Antes de tudo, o nó não é ótimo para arquivos estáticos, mas não é realmente o que deveria ser (use a ferramenta certa para o trabalho certo). Se alguém está preocupado com a velocidade de seus arquivos estáticos, deve usar uma CDN de qualquer maneira.
AlexGad

26

Os servidores NIO (Node.js etc.) tendem a ser mais rápidos que os servidores BIO. (IIS etc). Para apoiar minha reivindicação, a TechEmpower é uma empresa especializada em benchmarks de estrutura da web . Eles são muito abertos e têm uma maneira padrão de testar todas as estruturas de quadro.

Atualmente, os testes da Rodada 9 são os mais recentes (maio de 2014). Existem muitos tipos de IIS testados, mas o aspnet stripped parece ser a variante mais rápida do IIS.

Aqui estão os resultados em respostas por segundo ( quanto maior, melhor):

  • Serialização JSON
    • nodejs: 228,887
    • sem aspnet: 105,272
  • Consulta única
    • nodejs-mysql: 88,597
    • aspnet-stripped-raw: 47,066
  • Várias consultas
    • nodejs-mysql: 8,878
    • aspnet-stripped-raw: 3,915
  • Texto simples
    • nodejs: 289,578
    • sem aspnet: 109,136

Em todos os casos, o Node.js tende a ser 2x mais rápido que o IIS.


1
Exceto no teste de Múltiplas consultas, em que o ASPNET possui duas entradas (aspnet-stripped-raw e aspnet-mysql-raw) que superam o nodejs-mysql, que é a entrada principal do njs.
perfil

4
Bem, o teste de múltiplas consultas não está exatamente testando a velocidade do servidor. Ele está testando principalmente a velocidade do driver MySQL. O NodeJS usa principalmente bancos de dados NO-SQL como MongoDB, CouchDB. O driver MySQL pode não estar otimizado. Os testes de serialização e texto sem formatação Json tendem a fornecer velocidade pura ao servidor - eu confiaria mais neles.
23415 TTEKIN

e se eu usar o nó do IIS? é que meu desempenho será prejudicado ou será o mesmo.
Umashankar 30/08/19

3
Obrigado pelo link para a página de referência. A resposta, no entanto, pode precisar de uma atualização; as coisas podem ter mudado bastante com o advento do .NET Core 2.1. Por exemplo, o benchmark de serialização JSON 2018 lista o ASP.NET Core em 971.122 solicitações / s e o Node.js em 561.593 solicitações / s, então hoje o ASP.NET Core parece ser quase duas vezes mais rápido que o Node.js.
stakx - não está mais contribuindo com

13

Eu tenho que concordar com Marcus Granstrom, o cenário é muito importante aqui.

Para ser sincero, parece que você está tomando uma decisão arquitetônica de alto impacto. Meu conselho seria isolar as áreas de preocupação e fazer uma "pausa" entre as pilhas que você está considerando.

No final do dia, você é responsável pela decisão e não acho que a desculpa "Um cara do Stackoverflow me mostrou um artigo que dizia que seria bom" Vai resolver isso com seu chefe.


1
Estou procurando algo para convencer as pessoas (incluindo meu chefe) que vale a pena considerar como uma alternativa ao site MVC.net, para não convencê-las de que devemos trocar. Tudo o que descobri até agora são menções anedóticas que podem suportar mais carga e ter um desempenho melhor. Alguém realmente provou isso?
David Merrilees

17
Mas o que há de errado com o site MVC? POR QUE você está tentando encontrar uma alternativa? Essa é a pergunta mais importante. Se o problema for lento, sob forte carga simultânea, verifique se você está usando o async.net. Se ainda estiver muito lento, você precisará quebrar seu código e descobrir onde estão seus gargalos. Na minha experiência, não há uma enorme diferença entre a rede de nós e async nos cenários do REAL WORLD. Você pode alterar sua plataforma, mas provavelmente mudará um conjunto de gargalos / dores de cabeça de código para outro conjunto de gargalos / dores de cabeça de código.
AlexGad

1

A principal diferença que vejo é que o nó .js é uma linguagem de programação dinâmica (verificação de tipo), portanto, os tipos devem ser derivados em tempo de execução. As linguagens fortemente tipadas, como o C # .NET, teoricamente, têm muito mais chances de vencer a luta contra o Nó .js (e PHP etc.), especialmente onde é caro o cálculo. A propósito, o .NET deve ter melhor interoperação nativa com C / C ++ do que o nó .js.


4
Sua sugestão de que a digitação "fraca" em JS diminui a velocidade é errada e irrelevante e, independentemente disso, está comparando maçãs e pedras (até laranjas seriam mais parecidas com o que você está sugerindo).
rainabba

7
@rainabba Quando você compara algum tipo de computação (por exemplo, fibonacci de x), ele está completamente correto.
Stan

5
@steve Na verdade, dado Z, você ainda não pode dizer isso porque JS é uma linguagem e .Net é uma estrutura. São coisas completamente diferentes. Os tempos de execução do .Net são compilados para uma arquitetura de processador específica e, portanto, não é possível alterar significativamente o desempenho de um pedaço de código específico para uma única peça de hardware. Como a V8 demonstrou, o JS pode ser interpretado e executado e com velocidades extremamente variadas, e não há razão para pensar que um dia seu código de fibonacci escrito em JS não seja executado tão rápido quanto no código executado no CLR (provavelmente será Mais rápido). Maçãs e pedras; como eu disse.
rainabba

1
pode ser que você está certo, mas aos meus olhos, eu não sei outros países, na China, muitos programadores que entrevistei apenas conhecidos EF ou LINQ to SQL, estes quadros reduzir de .net desempenho significativamente
Dexiang

1
O mesmo pode ser dito para JS. enquanto JS estiver atualizando fibonacci, você realmente acha que o .NET permanecerá onde está esperando?
Quanben
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.