Nœud.js vs.Net performance

j'ai beaucoup lu sur Node.js être rapide et capable d'accueillir de grandes quantités de charge. Est-ce que quelqu'un a des preuves réelles de ceci par rapport à d'autres cadres, en particulier .Net? La plupart des articles que j'ai lus sont anecdotiques ou n'ont pas de comparaisons .Net.

Merci

163
demandé sur David Merrilees 2012-02-15 12:40:08

5 réponses

Être RAPIDE et de la manipulation de beaucoup de CHARGE sont deux choses différentes. Un serveur qui est vraiment FAST au service d'une requête par seconde pourrait totalement s'effondrer si vous lui envoyez 500 requêtes par seconde (sous LOAD ).

vous devez également considérer les pages statiques (et cachées) vs dynamiques. Si vous êtes inquiet au sujet des pages statiques, alors IIS va probablement battre noeud parce que IIS utilise la mise en cache en mode noyau, ce qui signifie que les requêtes qui demandent une page statique ne vont même pas sortir du noyau.

je suppose que vous cherchez une comparaison entre ASP.NET et le nœud. Dans cette bataille, après que tout a été compilé/interprété vous allez probablement être assez proche de la performance. Peut-être. NET est un peu plus rapide ou peut-être node est un peu plus rapide , mais il est probablement assez proche que vous n'avez pas de soins. J'aurais parié sur .NET, mais je n'en suis pas sûr.

l'endroit que le noeud est vraiment convaincant est pour la manipulation charge . C'est là que les technologies diffèrent vraiment. ASP.NET dédie un thread pour chaque requête à partir de son pool de threads, et une fois ASP.NET a épuisé toutes les demandes de threads disponibles commencent à se mettre en file d'attente. Si vous servez des applications" Hello World " comme l'exemple de @shankar, alors cela pourrait ne pas avoir beaucoup d'importance parce que les threads ne vont pas être bloqués et vous allez être en mesure de gérer un grand nombre de requêtes avant de manquer de threads. Le problème avec le ASP.NET model arrive lorsque vous commencez à faire des requêtes d'E/S qui bloquent le thread (appel à une DB, faire une requête 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, moins charge votre ASP.NET app va pouvoir servir.

pour empêcher ce blocage, vous utilisez les ports d'achèvement d'e/s qui n'ont pas besoin de tenir un thread pendant que vous attendez une réponse. ASP.NET supporte cela, mais malheureusement beaucoup de cadres/bibliothèques communs dans .NET ne le font pas. Par exemple, ADO.NET prend en charge les ports d'achèvement d'e/s, mais Entity Framework ne les utilise pas. Donc vous pouvez construire un ASP.NET application qui est purement asynchrone et gère beaucoup de charge, mais la plupart des gens ne le font pas parce que ce n'est pas aussi facile que de construire un c'est synchrone, et vous pourriez ne pas être en mesure d'utiliser certaines de vos parties préférées du cadre (comme linq to entities) si vous ne.

le problème est que ASP.NET (et le .net Framework) ont été créés pour être sans opinion sur asynchrone I/O. le réseau ne se soucie pas si vous écrivez du code synchrone ou asynchrone, donc c'est au développeur de prendre cette décision. Cela est dû en partie au fait que le filetage 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). Il est devenu encore plus difficile parce que .NET a fini avec 3-4 différents modèles pour faire async. .NET 4.5 essaie de revenir en arrière et d'adapter le .net framework pour avoir un modèle d'opinion autour de l'asynchrone, mais cela peut prendre un certain temps jusqu'à ce que les cadres dont vous vous souciez le soutiennent réellement.

les concepteurs de node d'autre part, fait un choix opiniâtre que tout I/O devrait être async. En raison de cette décision, les concepteurs de noeuds étaient également en mesure de prendre la décision que chaque instance de noeud serait filetée simple pour minimiser la commutation de thread, et qu'un thread exécuterait juste le code qui avait été mis en file d'attente. Ce pourrait être une nouvelle requête, ce pourrait être le rappel d'une requête DB, ce pourrait être le rappel d'une requête HTTP rest que vous avez faite. Node essaie de maximiser L'efficacité CPU en éliminant les commutateurs de contexte thread. Parce que noeud a fait ce choix opiniâtre que tout E/S est asynchrone, cela signifie aussi que tous ses cadres / add-ons supportent ce choix. Il est plus facile d'écrire des applications qui sont 100% asynchrones dans node (parce que node vous oblige à écrire des applications qui sont asynchrones).

encore une fois, je n'ai pas de nombres durs à prouver d'une manière ou d'une autre, mais je pense que noeud gagnerait la compétition de charge pour l'application web typique. Une application hautement optimisée (100% async) .NET peut donner le noeud équivalent.js application d'une course pour son argent, mais si vous avez pris une moyenne de toutes les .NET et tous le nœud applications, en moyenne, le noeud supporte probablement plus de charge.

Espère que ça aide.

354
répondu Matt Dotson 2017-08-08 13:02:55

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

mon matériel: Dell Latitude E6510, Core i5 (dual core), 8 Go RAM, Windows 7 Enterprise 64 bit OS

nœud de serveur

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

par défaut.htm

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

mon propre programme de test à l'aide de task parallel library:

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 (sur Windows). Il s'agit d'un test très rudimentaire, et nullement concluant. Mais je crois que c'est un bon point de départ. Nodejs est probablement plus rapide sur d'autres serveurs web, sur d'autres plateformes, mais sur Windows IIS est le gagnant. Les développeurs qui cherchent à convertir leurs ASP.NET MVC à nodejs devrait faire une pause et réfléchir à deux fois avant de continuer.

Mis à jour le (5/17/2012) Tomcat (sur windows) semble battre IIS hands down, environ 3 fois plus vite que IIS dans le développement de html statique.

tomcat

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 comparaison à plusieurs reprises. Tomcat semble être le serveur le plus rapide pour extraire du HTML statique, sous WINDOWS.

mise à Jour (5/18/2012) Auparavant, j'avais 100 000 demandes 10 000 demandes concurrentes. Je l'ai augmenté à 1 000 000 de demandes totales et 100 000 demandes simultanées. C'est moi qui gagne en hurlant, avec Nodejs qui frappe le pire. J'ai tabularized les résultats ci-dessous:

NodeJS vs IIS vs Tomcat serving STATIC HTML on WINDOWS .

47
répondu Shankar 2012-05-18 20:57:56

je suis d'accord avec Marcus Granstrom le scénario est très importante ici.

pour être honnête, on dirait que vous prenez une décision architecturale importante. Mon conseil serait d'isoler les domaines de préoccupation et de faire "cuire" entre ce que 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 type sur Stackoverflow m'a montré un article qui disait que bien" Couper avec votre patron.

11
répondu Number 9 2012-02-15 13:52:34

NIO serveurs (Nœud.js etc) ont tendance à être plus rapides que les serveurs BIO. (IIS etc). Pour appuyer ma demande, TechEmpower est une société spécialisée sur web framework benchmarks . Ils sont très ouverts et ont une façon standard de tester tous les cadres.

Ronde 9 tests sont actuellement la dernière (Mai 2014). Il ya beaucoup de saveurs IIS testés, mais aspnet-stripped semble être la variante la plus rapide IIS.

Voici les résultats en réponses par seconde (plus c'est mieux):

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

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

11
répondu ttekin 2018-04-09 10:41:36

principale différence ce que je vois c'est ce noeud .js est un langage de programmation dynamique (vérification de type), les types doivent donc être dérivés de l'exécution. Les langues fortement tapées comme C#. NET A théoriquement beaucoup plus de potentiel gagne la lutte contre le noeud .js (et PHP etc.), en particulier lorsqu'est coûteuse en calcul. En passant, le .NET devrait avoir une meilleure interopération native avec C/C++ que node .js.

1
répondu Ondrej Rozinek 2013-08-22 21:19:03