Node.js vs .Net rendimiento

183

He leído mucho acerca de que Node.js es rápido y capaz de acomodar grandes cantidades de carga. ¿Alguien tiene alguna evidencia del mundo real de este vs otros marcos, particularmente .Net? La mayoría de los artículos que he leído son anecdóticos o no tienen comparaciones con .Net.

Gracias

David Merrilees
fuente
1
¿Podría ser más preciso en qué tipo de escenario estamos hablando?
Marcus Granström
1
Estoy interesado en cualquier comparación de rendimiento de .Net y Node.js para aplicaciones web comparables que se ejecutan en IIS.
David Merrilees
1
No puedo imaginar a nadie construyendo un sitio web que tenga un alto rendimiento. requisitos fuera de .Net. El problema más básico con el que te encontrarás es que no será muy rentable en términos de licencia, ya que tiene un alto rendimiento. los sitios generalmente requieren escalamiento horizontal. Y no, no soy un enemigo de .Net. .Net paga las cuentas.
Shane Courtrille
44
Tuve que hacer pruebas internas de una pequeña API REST usando Node / express / mongo y el nuevo .net webapi / mongo y hubo diferencias de rendimiento basadas en lo que el cliente quería, pero al final del día, no lo suficiente como para hacer un diferencia. Necesita desarrollar sus propias pruebas basadas en sus propios escenarios. Nos llevó tres días escribir las diferentes API en ambos idiomas y luego otro par de días para configurar correctamente las pruebas. Si está planeando hacer algo remotamente serio, le sugiero que configure pruebas basadas en sus requisitos y decida usted mismo cuál es mejor para su carga.
AlexGad
55
@ShaneCourtrille Estás confundiendo .Net (un framework) y Windows (un sistema operativo). Son cosas muy diferentes y NO hay requisitos de licencia para .Net (que se ejecuta bastante bien en Linux como Mono).
rainabba

Respuestas:

366

Ser RÁPIDO y manejar mucha CARGA son dos cosas diferentes. Un servidor que es realmente RÁPIDO para atender una solicitud por segundo podría ser totalmente malicioso si le envía 500 solicitudes por segundo (bajo CARGAR ).

También debe considerar las páginas estáticas (y en caché) frente a las dinámicas. Si le preocupan las páginas estáticas, entonces IIS probablemente va a vencer al nodo porque IIS usa el almacenamiento en caché en modo kernel, lo que significa que las solicitudes que solicitan una página estática ni siquiera saldrán del kernel.

Supongo que está buscando una comparación entre ASP.NET y el nodo. En esta batalla, después de que todo haya sido compilado / interpretado, es probable que tengas un rendimiento bastante cercano. Tal vez .NET sea un poco más RÁPIDO o tal vez el nodo sea un poco MÁS RÁPIDO , pero probablemente esté lo suficientemente cerca como para que no te importe. Apostaría en .NET, pero no estoy seguro.

El lugar en el que ese nodo es realmente convincente es para manejar LOAD . Aquí es donde las tecnologías realmente difieren. ASP.NET dedica un subproceso para cada solicitud de su grupo de subprocesos, y una vez que ASP.NET se ha agotado, todas las solicitudes de subprocesos disponibles comienzan a ponerse en cola. Si está sirviendo aplicaciones "Hello World" como el ejemplo de @shankar, entonces esto podría no importar mucho porque los hilos no serán bloqueados y podrá manejar muchas solicitudes antes que usted quedarse sin hilos. El problema con el modelo ASP.NET se produce cuando comienza a realizar solicitudes de E / S que bloquean el hilo (llamar a una base de datos, realizar una solicitud http a un servicio, leer un archivo del disco). Estas solicitudes de bloqueo significan que su valioso hilo del grupo de hilos no está haciendo nada. Cuanto más bloqueo tengas,CARGUE su aplicación ASP.NET podrá servir.

Para evitar este bloqueo, utiliza puertos de finalización de E / S que no requieren mantener un hilo mientras espera una respuesta. ASP.NET admite esto, pero desafortunadamente muchos de los frameworks / bibliotecas comunes en .NET NO. Por ejemplo, ADO.NET admite puertos de finalización de E / S, pero Entity Framework no los usa. Por lo tanto, puede crear una aplicación ASP.NET que sea puramente asíncrona y maneje mucha carga, pero la mayoría de las personas no lo hacen porque no es tan fácil como construir una que sea síncrona, y es posible que no pueda usar algunas de sus partes favoritas del marco (como linq a entidades) si lo hace.

El problema es que ASP.NET (y .NET Framework) se crearon para no tener opiniones sobre las E / S asíncronas. A .NET no le importa si escribe código síncrono o asíncrono, por lo que depende del desarrollador tomar esta decisión. Parte de esto se debe a que el enhebrado y la programación con operaciones asincrónicas se consideraba "difícil", y .NET quería hacer felices a todos (novatos y expertos). Se puso aún más difícil porque .NET terminó con 3-4 patrones diferentes para hacer asíncrono. .NET 4.5 está tratando de retroceder y adaptar el .NET Framework para tener un modelo obstinado alrededor de IO asíncrono, pero puede pasar un tiempo hasta que los marcos que le interesan realmente lo admitan.

Los diseñadores de nodos, por otro lado, tomaron una decisión obvia de que TODAS las E / S deberían ser asíncronas. Debido a esta decisión, los diseñadores de nodos también pudieron tomar la decisión de que cada instancia del nodo sería de un solo subproceso para minimizar el cambio de subproceso, y que un subproceso simplemente ejecutaría el código que se había puesto en cola. Esa podría ser una nueva solicitud, podría ser la devolución de llamada de una solicitud de base de datos, podría ser la devolución de llamada de una solicitud de reposo http que realizó. Node intenta maximizar la eficiencia de la CPU eliminando los cambios de contexto de subproceso. Debido a que el nodo tomó esta decisión obvia de que TODAS las E / S son asíncronas, eso también significa que todos sus marcos / complementos admiten esta opción. Es más fácil escribir aplicaciones que son 100% asíncronas en el nodo (porque el nodo lo obliga a escribir aplicaciones que son asíncronas).

Nuevamente, no tengo ningún número difícil para probar de una forma u otra, pero creo que el nodo ganaría la competencia LOAD para la aplicación web típica. Una aplicación .NET altamente optimizada (100% asíncrona) podría ejecutar la aplicación node.js equivalente por su dinero, pero si toma un promedio de todas las aplicaciones .NET y todas las aplicaciones de nodo, en promedio, el nodo probablemente maneja más CARGA.

Espero que ayude.

Matt Dotson
fuente
39
Recuerde que ASP.NET ha soportado controladores de solicitudes asíncronas durante mucho tiempo, y con MVC4 se han vuelto extremadamente fáciles de usar.
fabspro
12
"Estas solicitudes de bloqueo significan que su valioso subproceso del grupo de subprocesos no está haciendo nada. Cuanto más bloqueo tenga, menos CARGAR será capaz de servir su aplicación ASP.NET". ¿Por qué importa si hacemos cola por adelantado (la solicitud entrante) o en el backend (el hilo de trabajo real)? Pase lo que pase, la solicitud del cliente está esperando la respuesta. Creo que la clave que la gente pasa por alto en este debate es el "rendimiento". No se trata de cuántas conexiones simultáneas tiene un servidor, es qué tan rápido puede responder a cada solicitud, ¿verdad?
sjdirect
19
// No me deja editar mi comentario, así que esto es lo que quería decir. // @sjdirect: el rendimiento no es lo mismo que el tiempo de respuesta. Tiene razón en preocuparse por el tiempo de respuesta, pero es una elección entre tiempo de cola + tiempo de respuesta, o solo tiempo de respuesta. El procesamiento de la solicitud tomará el mismo tiempo en ambos escenarios (la ejecución sincrónica NO hará que su solicitud de base de datos se ejecute más rápido), pero si sus hilos de solicitud están bloqueados, entonces también está agregando tiempo de cola a las solicitudes porque ni siquiera puede comenzar a procesar la solicitud hasta que se hayan completado las solicitudes anteriores.
Matt Dotson
66
Esto fue realmente informativo, ¡gracias! Sin embargo, una cosa a tener en cuenta es que Entity Framework 6 (actualmente RC1) ahora admite el patrón asincrónico de .NET 4.5. msdn.microsoft.com/en-us/data/jj819165
parlamento
44
¡Esto es muy especulativo! Sería genial tener datos. Así es como decido cómo proceder con los temas de rendimiento.
kingPuppy
50

Hice una prueba de rendimiento rudimentaria entre nodejs e IIS. IIS es aproximadamente 2,5 veces más rápido que nodejs cuando se distribuye "¡hola, mundo!". código a continuación.

mi hardware: Dell Latitude E6510, Core i5 (doble núcleo), 8 GB de RAM, sistema operativo Windows 7 Enterprise de 64 bits

servidor de nodo

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>

mi propio programa de referencia utilizando la biblioteca paralela de tareas:

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

}
}

y 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

conclusión: IIS es más rápido que nodejs en aproximadamente 2.5 veces (en Windows). Esta es una prueba muy rudimentaria, y de ninguna manera concluyente. Pero creo que este es un buen punto de partida. Nodejs es probablemente más rápido en otros servidores web, en otras plataformas, pero en Windows IIS es el ganador. Los desarrolladores que deseen convertir su MVC de ASP.NET a nodejs deberían detenerse y pensar dos veces antes de continuar.

Actualizado (17/05/2012) Tomcat (en Windows) parece vencer a IIS, aproximadamente 3 veces más rápido que IIS al distribuir html estático.

gato

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

resultados de 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

Conclusión actualizada: ejecuté el programa de referencia varias veces. Tomcat parece ser el servidor más rápido en distribuir HTML ESTÁTICO EN VENTANAS.

Actualizado (18/05/2012) Anteriormente tenía 100,000 solicitudes totales con 10,000 solicitudes concurrentes. Lo aumenté a 1,000,000 de solicitudes totales y 100,000 solicitudes concurrentes. IIS sale como el ganador a gritos, con Nodejs cazando lo peor. He tabulado los resultados a continuación:

NodeJS vs IIS vs Tomcat que sirven HTML ESTÁTICO en WINDOWS.

Shankar
fuente
56
Estás comparando manzanas con gatos. Compare Node.js con ASP.NET MVC. A lo sumo, IIS es más rápido al servir archivos estáticos, aunque lo dudo mucho.
alessioalex
12
@alessioalex: no entiendo por qué esta comparación no es válida. Estoy comparando los tiempos de respuesta para html estático. IIS está distribuyendo html estático desde default.htm, mientras que el servidor nodejs está distribuyendo la misma cadena e IIS sale adelante. La comparación de una aplicación ASP.NET MVC requeriría más esfuerzo y tiempo, y planeo hacerlo más tarde.
Shankar
28
Ok, digamos que IIS es mejor para servir archivos estáticos en Windows que Node. IIS solo sirve archivos estáticos y tales (como Apache o NGINX), Node hace mucho más que eso. Debería comparar ASP.NET MVC con Node (consultar la base de datos, recuperar datos de un servicio externo, etc., etc.). Verá grandes ganancias de rendimiento con Node sobre ASP.NET MVC.
alessioalex
27
Si va a hacer esto, al menos comprenda la naturaleza del nodo. Un proceso de Nodo solo puede usar un solo núcleo. Entonces, lo que está comparando es un proceso de nodo que se ejecuta en un núcleo a un proceso IIS y tomcat que usa múltiples núcleos. Para comparar correctamente, debe ejecutar un nodo agrupado. Consulte nodejs.org/api/cluster.html para obtener una solución de clúster fácil de usar. Sin embargo, puedo decirle por experiencia, la diferencia entre nodo y async c # es 10-15% de cualquier manera, dependiendo de lo que esté haciendo.
AlexGad
14
Además, probar archivos estáticos con nodo e IIS y Tomcat no tiene sentido. En primer lugar, el nodo no es ideal para archivos estáticos, pero en realidad no está destinado a serlo (use la herramienta adecuada para el trabajo correcto). Si alguien está preocupado por la velocidad de sus archivos estáticos, debería usar un CDN de todos modos.
AlexGad
26

Los servidores NIO (Node.js, etc.) tienden a ser más rápidos que los servidores BIO. (IIS, etc.) Para respaldar mi reclamo, TechEmpower es una compañía especializada en puntos de referencia de framework web . Son muy abiertos y tienen una forma estándar de probar todos los framewrks.

Las pruebas de la ronda 9 son actualmente las últimas (mayo de 2014). Hay muchos sabores de IIS probados, pero la aspirina despojada parece ser la variante de IIS más rápida.

Aquí están los resultados en respuestas por segundo (más alto es mejor):

  • Serialización JSON
    • nodejs: 228,887
    • despojado de aspnet: 105,272
  • Consulta única
    • nodejs-mysql: 88,597
    • aspnet-stripped-raw: 47,066
  • Múltiples consultas
    • nodejs-mysql: 8,878
    • aspnet-stripped-raw: 3,915
  • Texto sin formato
    • nodejs: 289,578
    • despojado de aspnet: 109,136

En todos los casos, Node.js tiende a ser 2 veces más rápido que IIS.

ttekin
fuente
1
Excepto en la prueba de Consultas múltiples, donde ASPNET tiene dos entradas (aspnet-stripped-raw y aspnet-mysql-raw) que superaron a nodejs-mysql, que es la entrada njs superior.
GalacticCowboy
44
Bueno, la prueba de consultas múltiples no prueba exactamente la velocidad del servidor. Principalmente está probando la velocidad del controlador MySQL. NodeJS utiliza principalmente bases de datos NO-SQL como MongoDB, CouchDB. El controlador MySQL podría no estar optimizado. La serialización de Json y las pruebas de texto sin formato tienden a dar la velocidad pura del servidor; confiaría más en ellas.
ttekin 02 de
¿Qué pasa si uso el nodo IIS? Es mi rendimiento se degradará o será el mismo.
Umashankar
3
Gracias por el enlace a la página de referencia. Sin embargo, la respuesta podría necesitar una actualización, las cosas pueden haber cambiado bastante con la llegada de .NET Core 2.1. Por ejemplo, el punto de referencia de serialización JSON 2018 enumera ASP.NET Core a 971,122 solicitudes / segundo y Node.js a 561,593 solicitudes / segundo, por lo que hoy ASP.NET Core parece ser casi el doble de rápido que Node.js a ese respecto.
stakx - ya no contribuye el
13

Tengo que estar de acuerdo con Marcus Granstrom, el escenario es muy importante aquí.

Para ser sincero, parece que está tomando una decisión arquitectónica de alto impacto. Mi consejo sería aislar las áreas de preocupación y hacer un "horneado" entre las pilas que esté considerando.

Al final del día, usted es responsable de la decisión y no creo que la excusa "Un tipo en Stackoverflow me mostró un artículo que decía que estaría bien".

Número 9
fuente
1
Estoy buscando algo para convencer a las personas (incluido mi jefe) que vale la pena considerar como una alternativa a un sitio web MVC.net, no para convencerlos de que deberíamos intercambiar. Todo lo que he encontrado hasta ahora son menciones anecdóticas de que puede soportar más carga y funciona mejor. ¿Alguien ha demostrado esto realmente?
David Merrilees
17
Pero, ¿qué tiene de malo el sitio web de MVC? ¿POR QUÉ estás tratando de encontrar una alternativa? Esa es la pregunta más importante. Si el problema es que es lento bajo una gran carga concurrente, entonces debes asegurarte de estar usando async.net. Si todavía es muy lento, entonces necesita desglosar su código y descubrir dónde están sus cuellos de botella. En mi experiencia, no hay una gran diferencia entre el nodo y la red asíncrona en los escenarios del mundo real. Puede cambiar su plataforma, pero es probable que simplemente cambie un conjunto de cuellos de botella / dolores de cabeza de código por otro conjunto de cuellos de botella / dolores de cabeza de código.
AlexGad
1

La principal diferencia que veo es que el nodo .js es un lenguaje de programación dinámico (verificación de tipo), por lo que los tipos deben derivarse en tiempo de ejecución. Los lenguajes fuertemente tipados como C # .NET teóricamente tienen mucho más potencial gana la lucha contra el Nodo .js (y PHP, etc.), especialmente cuando es un cálculo costoso. Por cierto, .NET debería tener una mejor interoperación nativa con C / C ++ que el nodo .js.

Ondrej Rozinek
fuente
44
Su sugerencia de que el tipeo "débil" en JS lo ralentiza es incorrecto e irrelevante e independientemente, eso es comparar manzanas y piedras (incluso las naranjas serían más similares de lo que sugiere).
rainabba 01 de
77
@rainabba Cuando compara el cálculo de algún tipo (por ejemplo, fibonacci de x), él es completamente correcto.
Stan
55
@steve En realidad, dado Z, todavía no puedes decir eso porque JS es un lenguaje y .Net es un marco. Son cosas completamente diferentes. Los tiempos de ejecución .Net se compilan para una arquitectura de procesador particular, por lo que no puede cambiar el rendimiento de un fragmento de código en particular de manera significativa para una sola pieza de hardware. Como muestra V8, JS se puede interpretar y ejecutar a velocidades extremadamente variables y no hay razón para pensar que un día su código de Fibonacci escrito en JS no se ejecutará SOLO tan rápido como con el código que se ejecuta a través del CLR (probablemente, será Más rápido). Manzanas y piedras; como ya he dicho.
rainabba
1
Puede ser que usted tiene razón, pero en mi vista, no sé otros países, en China, muchos muchos programadores que entrevisté simplemente conocido EF o LINQ to SQL, estos marcos reducen el rendimiento de .NET significativamente
Dexiang
1
Lo mismo se puede decir a JS. mientras JS se está poniendo al día con fibonacci, ¿realmente crees que .NET permanecerá donde está esperando?
quanben