Node.js vs performances .Net

183

J'ai beaucoup lu sur Node.js étant rapide et capable de supporter de grandes quantités de charge. Quelqu'un a-t-il des preuves concrètes de cela par rapport à d'autres frameworks, en particulier .Net? La plupart des articles que j'ai lus sont anecdotiques ou n'ont pas de comparaison avec .Net.

Merci

David Merrilees
la source
1
Pourriez-vous être plus précis dans quel genre de scénario nous parlons?
Marcus Granström
1
Je suis intéressé par toute comparaison de performances de .Net et Node.js pour des applications Web comparables exécutées dans IIS.
David Merrilees
1
Je ne peux pas imaginer que quiconque construise un site Web à haute performance. exigences hors de .Net. Le problème le plus fondamental que vous rencontrez est que cela ne sera pas très rentable en termes de licence depuis une haute performance. les sites nécessitent généralement une mise à l'échelle. Et non, je ne suis pas un haineux .Net. .Net paie les factures.
Shane Courtrille
4
J'ai dû faire des tests internes d'une petite API REST en utilisant Node / express / mongo et le nouveau .net webapi / mongo et il y avait des différences de perf en fonction de ce que le client voulait, mais en fin de compte, pas assez pour faire un différence. Vous devez développer vos propres tests en fonction de vos propres scénarios. Il nous a fallu trois jours pour écrire les différentes API dans les deux langues, puis quelques jours supplémentaires pour configurer correctement les tests. Si vous envisagez de faire quelque chose de sérieux à distance, je suggérerais de mettre en place des tests en fonction de vos besoins et de décider par vous-même de ce qui convient le mieux à votre charge.
AlexGad
5
@ShaneCourtrille Vous confondez .Net (un framework) et Windows (un système d'exploitation). Ce sont des choses très différentes et il n'y a AUCUNE exigence de licence pour .Net (qui fonctionne assez bien sous Linux en tant que Mono).
rainabba

Réponses:

366

Être RAPIDE et gérer beaucoup de CHARGE sont deux choses différentes. Un serveur qui répond vraiment RAPIDEMENT à une requête par seconde peut totalement croasser si vous lui envoyez 500 requêtes par seconde (sous CHARGE ).

Vous devez également considérer les pages statiques (et mises en cache) par rapport aux pages dynamiques. Si vous êtes préoccupé par les pages statiques, alors IIS va probablement battre le nœud car IIS utilise la mise en cache en mode noyau, ce qui signifie que les requêtes qui demandent une page statique ne sortiront même pas du noyau.

Je suppose que vous recherchez une comparaison entre ASP.NET et node. Dans cette bataille, une fois que tout a été compilé / interprété, vous serez probablement assez proche des performances. Peut-être que .NET est un peu plus rapide ou peut-être que le nœud est un peu plus rapide , mais il est probablement suffisamment proche pour que vous ne vous en souciez pas. Je parierais sur .NET, mais je ne sais pas avec certitude.

L'endroit où ce nœud est vraiment convaincant est la gestion de LOAD que votre application ASP.NET va pouvoir servir. LOAD . C'est là que les technologies diffèrent vraiment. ASP.NET dédie un thread pour chaque demande de son pool de threads, et une fois qu'ASP.NET a épuisé toutes les demandes de threads disponibles commencent à être mises en file d'attente. Si vous diffusez des applications "Hello World" comme l'exemple de @shankar, cela n'a peut-être pas d'importance car les fils ne seront pas bloqués et vous serez en mesure de traiter un grand nombre de demandes avant vous manquer de threads. Le problème avec le modèle ASP.NET survient lorsque vous commencez à faire des demandes d'E / S qui bloquent le thread (appel à une base de données, faire une demande http à un service, lire un fichier à partir du disque). Ces demandes de blocage signifient que votre précieux thread du pool de threads ne fait rien. Plus vous avez de blocage,

Pour éviter ce blocage, vous utilisez des ports d'achèvement d'E / S qui ne nécessitent pas de maintenir un thread pendant que vous attendez une réponse. ASP.NET prend en charge cela, mais malheureusement, de nombreux frameworks / bibliothèques courants dans .NET NE SONT PAS. Par exemple, ADO.NET prend en charge les ports d'achèvement d'E / S, mais Entity Framework ne les utilise pas. Vous pouvez donc créer une application ASP.NET qui est purement asynchrone et gère beaucoup de charge, mais la plupart des gens ne le font pas, car ce n'est pas aussi facile que de créer une application synchrone, et vous ne pourrez peut-être pas utiliser certaines de vos parties préférées. du framework (comme linq aux entités) si vous le faites.

Le problème est que ASP.NET (et le .NET Framework) ont été créés pour ne pas se prononcer sur les E / S asynchrones. .NET ne se soucie pas si vous écrivez du code synchrone ou asynchrone, c'est donc au développeur de prendre cette décision. Cela s'explique en partie par le fait que le threading et la programmation avec des opérations asynchrones étaient considérés comme «difficiles», et .NET voulait rendre tout le monde heureux (noobs et experts). Cela est devenu encore plus difficile car .NET s'est retrouvé avec 3-4 modèles différents pour faire l'asynchrone. .NET 4.5 essaie de revenir en arrière et de moderniser le framework .NET pour avoir un modèle d'opinion autour des E / S asynchrones, mais cela peut prendre un certain temps avant que les frameworks qui vous intéressent le prennent réellement en charge.

Les concepteurs du nœud, quant à eux, ont fait un choix avisé selon lequel TOUTES les E / S devraient être asynchrones. En raison de cette décision, les concepteurs de nœuds ont également pu prendre la décision que chaque instance de nœud serait un thread unique pour minimiser le changement de thread, et qu'un thread exécuterait simplement le code qui avait été mis en file d'attente. Cela peut être une nouvelle requête, ce peut être le rappel d'une requête DB, cela peut être le rappel d'une requête de repos http que vous avez effectuée. Node essaie de maximiser l'efficacité du processeur en éliminant les changements de contexte de thread. Parce que node a fait ce choix avisé que TOUTES les E / S sont asynchrones, cela signifie également que tous ses frameworks / modules complémentaires prennent en charge ce choix. Il est plus facile d'écrire des applications qui sont 100% asynchrones dans le nœud (car le nœud vous oblige à écrire des applications asynchrones).

Encore une fois, je n'ai pas de chiffres précis pour prouver d'une manière ou d'une autre, mais je pense que node gagnerait le concours LOAD pour l'application Web typique. Une application .NET hautement optimisée (100% asynchrone) peut donner à l'application node.js équivalente une course pour son argent, mais si vous prenez une moyenne de tous les .NET et de toutes les applications de nœuds, en moyenne, le nœud gère probablement plus CHARGE.

J'espère que cela pourra aider.

Matt Dotson
la source
39
N'oubliez pas qu'ASP.NET prend en charge les gestionnaires de requêtes asynchrones depuis longtemps et qu'avec MVC4, ils sont devenus extrêmement simples à utiliser.
fabspro
12
"Ces demandes de blocage signifient que votre précieux thread du pool de threads ne fait rien. Plus vous avez de blocage, moins votre application ASP.NET sera en mesure de servir." Pourquoi est-ce important que nous soyons en file d'attente à l'avant (la demande entrante) ou dans le backend (le thread de travail réel)? Quoi qu'il en soit, la demande du client attend la réponse. Je pense que la clé que les gens négligent dans ce débat est le «débit». Il ne s'agit pas du nombre de connexions simultanées qu'un serveur détient, de la vitesse à laquelle il peut répondre à chaque demande, n'est-ce pas?
sjdirect
19
// Ne me laisse pas modifier mon commentaire, alors voici ce que je voulais dire: // @sjdirect - Le débit n'est pas le même que le temps de réponse. Vous avez raison de vous soucier du temps de réponse, mais c'est un choix entre le temps de file d'attente + le temps de réponse, ou simplement le temps de réponse. Le traitement de la demande prendra autant de temps dans les deux scénarios (l'exécution synchrone ne fera PAS exécuter votre demande de base de données plus rapidement), mais si vos threads de demande sont bloqués, vous ajoutez également du temps de file d'attente aux demandes. car vous ne pouvez même pas commencer le traitement de la demande tant que les demandes précédentes ne sont pas terminées.
Matt Dotson
6
C'était vraiment instructif, merci! Une chose à noter cependant est qu'Entity Framework 6 (actuellement RC1) prend désormais en charge le modèle asynchrone de .NET 4.5. msdn.microsoft.com/en-us/data/jj819165
parlement le
4
C'est extrêmement spéculatif! Ce serait formidable d'avoir des données. C'est généralement ainsi que je décide de la manière de procéder avec les sujets de performance.
kingPuppy
50

J'ai fait un test de performance rudimentaire entre nodejs et IIS. IIS est environ 2,5 fois plus rapide que nodejs lors de la distribution de "hello, world!". code ci-dessous.

mon matériel: Dell Latitude E6510, Core i5 (double cœur), 8 Go de RAM, système d'exploitation Windows 7 Entreprise 64 bits

serveur de nœuds

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>

mon propre programme de référence utilisant la bibliothèque parallèle de tâches:

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

}
}

et résultats:

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

conclusion: IIS est plus rapide que nodejs d'environ 2,5 fois (sous Windows). C'est un test très rudimentaire, et en aucun cas concluant. Mais je pense que c'est un bon point de départ. Nodejs est probablement plus rapide sur d'autres serveurs Web, sur d'autres plates-formes, mais sur Windows, IIS est le gagnant. Les développeurs souhaitant convertir leur ASP.NET MVC en nodejs doivent faire une pause et réfléchir à deux fois avant de continuer.

Mise à jour (17/05/2012) Tomcat (sur Windows) semble battre IIS haut la main, environ 3 fois plus rapide que IIS pour fournir du HTML statique.

matou

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

résultats 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

conclusion mise à jour: j'ai exécuté le programme de référence plusieurs fois. Tomcat semble être le serveur le plus rapide dans la distribution de HTML STATIQUE, SOUS WINDOWS.

Mise à jour (18/05/2012) Auparavant, j'avais 100 000 demandes au total avec 10 000 demandes simultanées. Je l'ai augmenté à 1 000 000 demandes totales et 100 000 demandes simultanées. IIS sort comme le vainqueur criant, avec Nodejs carénant le pire. J'ai tabularisé les résultats ci-dessous:

NodeJS vs IIS vs Tomcat servant du HTML STATIQUE sous WINDOWS.

Shankar
la source
56
Vous comparez des pommes avec des chats. Comparez Node.js avec ASP.NET MVC. Au plus IIS est plus rapide pour servir des fichiers statiques, même si j'en doute sérieusement.
alessioalex
12
@alessioalex: je ne comprends pas pourquoi cette comparaison n'est pas valide. je compare les temps de réponse pour le HTML statique. IIS distribue du code HTML statique à partir de default.htm, tandis que le serveur nodejs distribue la même chaîne et IIS sort en tête. Comparer une application ASP.NET MVC exigerait plus d'efforts et de temps, et je prévois de le faire plus tard.
Shankar
28
Ok, disons qu'IIS est meilleur pour servir des fichiers statiques sur Windows que Node. IIS ne sert que des fichiers statiques et autres (comme Apache ou NGINX), Node fait bien plus que cela. Vous devez comparer ASP.NET MVC avec Node (interrogation de la base de données, récupération de données à partir d'un service externe, etc.). Vous verrez d'énormes gains de performances avec Node sur ASP.NET MVC.
alessioalex
27
Si vous comptez faire cela, veuillez au moins comprendre la nature du nœud. Un processus Node ne peut utiliser qu'un seul cœur. Donc, ce que vous comparez est un processus de nœud s'exécutant sur un cœur à un processus IIS et tomcat utilisant plusieurs cœurs. Afin de comparer correctement, vous devez exécuter le nœud en cluster. Voir nodejs.org/api/cluster.html pour une solution de cluster simple à utiliser. Cependant, je peux vous dire par expérience que la différence entre node et async c # est de 10 à 15% dans les deux cas en fonction de ce que vous faites.
AlexGad
14
De plus, tester des fichiers statiques avec node, IIS et Tomcat n'a pas de sens. Tout d'abord, node n'est pas idéal pour les fichiers statiques, mais ce n'est pas vraiment censé l'être (utilisez le bon outil pour le bon travail). Si quelqu'un s'inquiète de la vitesse de ses fichiers statiques, il devrait de toute façon utiliser un CDN.
AlexGad
26

Les serveurs NIO (Node.js, etc.) ont tendance à être plus rapides que les serveurs BIO. (IIS, etc.). Pour étayer ma réclamation, TechEmpower est une société spécialisée dans les benchmarks de framework web . Ils sont très ouverts et ont une manière standard de tester tous les cadres.

Les tests du Round 9 sont actuellement les plus récents (mai 2014). Il existe de nombreuses versions IIS testées, mais aspnet-stripped semble être la variante IIS la plus rapide.

Voici les résultats en réponses par seconde (plus élevé est meilleur):

  • Sérialisation JSON
    • nodejs: 228,887
    • aspnet-dépouillé: 105,272
  • Requête unique
    • nodejs-mysql: 88,597
    • aspnet-stripped-raw: 47,066
  • Requêtes multiples
    • nodejs-mysql: 8,878
    • aspnet-stripped-raw: 3,915
  • Texte brut
    • nodejs: 289,578
    • aspnet-dépouillé: 109,136

Dans tous les cas, Node.js a tendance à être 2x + plus rapide que IIS.

ttekin
la source
1
Sauf sur le test de requêtes multiples, où ASPNET a deux entrées (aspnet-stripped-raw et aspnet-mysql-raw) qui battent toutes les deux nodejs-mysql, qui est la première entrée njs.
GalacticCowboy
4
Eh bien, le test de requêtes multiples ne teste pas exactement la vitesse du serveur. Il teste principalement la vitesse du pilote MySQL. NodeJS utilise principalement des bases de données NO-SQL comme MongoDB, CouchDB. Le pilote MySQL n'est peut-être pas optimisé. La sérialisation Json et les tests Plaintext ont tendance à donner la vitesse du serveur pur - je leur ferais plus confiance.
ttekin
et si j'utilise le nœud IIS? est ma performance se dégradera ou sera la même.
Umashankar
3
Merci pour le lien vers la page de référence. La réponse pourrait cependant nécessiter une mise à jour, les choses ont peut-être beaucoup changé avec l'avènement de .NET Core 2.1. Par exemple, le benchmark de sérialisation JSON 2018 répertorie ASP.NET Core à 971122 requêtes / s et Node.js à 561593 requêtes / s, de sorte qu'aujourd'hui, ASP.NET Core semble être presque deux fois plus rapide que Node.js à cet égard.
stakx - ne contribue plus
13

Je suis d'accord avec Marcus Granstrom, le scénario est très important ici.

Pour être honnête, il semble que vous preniez une décision architecturale à fort impact. Mon conseil serait d'isoler les zones de préoccupation et de faire un «bake off» entre les piles que vous envisagez.

À la fin de la journée, vous êtes responsable de la décision et je ne pense pas que l'excuse "Un gars sur Stackoverflow m'a montré un article qui disait que tout irait bien" va le couper avec votre patron.

Numéro 9
la source
1
Je cherche quelque chose pour convaincre les gens (y compris mon patron) qu'il vaut la peine de considérer comme une alternative à un site Web MVC.net, pas pour les convaincre que nous devrions échanger. Tout ce que j'ai trouvé jusqu'à présent, ce sont des mentions anecdotiques selon lesquelles il peut supporter plus de charge et fonctionne mieux. Quelqu'un a-t-il réellement prouvé cela?
David Merrilees
17
Mais quel est le problème avec le site Web MVC? POURQUOI essayez-vous de trouver une alternative? C'est la question la plus importante. Si le problème est qu'il est lent avec une charge simultanée importante, vous devez vous assurer que vous utilisez async.net. S'il est encore très lent, vous devez décomposer votre code et déterminer où se trouvent vos goulots d'étranglement. D'après mon expérience, il n'y a pas de différence énorme entre le nœud et le réseau asynchrone dans les scénarios REAL WORLD. Vous pouvez changer votre plate-forme, mais vous changerez probablement simplement un ensemble de goulots d'étranglement / maux de tête de code pour un autre ensemble de goulots d'étranglement / maux de tête de code.
AlexGad
1

La principale différence, ce que je vois, c'est que node .js est un langage de programmation dynamique (vérification de type), donc les types doivent être dérivés au moment de l'exécution. Les langages fortement typés comme C # .NET ont théoriquement beaucoup plus de potentiel pour gagner la bataille contre Node .js (et PHP etc.), surtout là où le calcul est coûteux. Au fait, le .NET devrait avoir une meilleure interopérabilité native avec C / C ++ que le nœud .js.

Ondrej Rozinek
la source
4
Votre suggestion que la saisie "faible" dans JS le ralentit est erronée et non pertinente et peu importe, c'est comparer des pommes et des pierres (même les oranges seraient plus similaires que ce que vous suggérez).
rainabba
7
@rainabba Lorsque vous comparez un calcul quelconque (par exemple fibonacci de x), il est tout à fait correct.
Stan
5
@steve En fait, étant donné Z, vous ne pouvez toujours pas dire cela car JS est un langage et .Net est un framework. Ce sont des choses complètement différentes. Les environnements d'exécution .Net sont compilés pour une architecture de processeur particulière et vous ne pouvez donc pas modifier de manière significative les performances d'un morceau de code particulier pour un seul morceau de matériel. Comme le montre V8, JS peut être interprété et exécuté à des vitesses extrêmement variables et il n'y a aucune raison de penser qu'un jour votre code fibonacci écrit en JS ne fonctionnera pas JUSTE aussi vite qu'avec du code exécuté via le CLR (probablement, ce sera plus rapide). Pommes et pierres; comme j'ai dit.
rainabba
1
peut-être avez-vous raison, mais à mon avis, je ne connais pas d'autres pays, en Chine, de nombreux programmeurs que j'ai interviewés juste connus EF ou Linq to Sql, ces frameworks réduisent considérablement les performances de .net
dexiang
1
La même chose peut être dite à JS. pendant que JS rattrape fibonacci, pensez-vous vraiment que .NET restera là où il attend?
quanben