Node.js против производительности .Net - PullRequest
172 голосов
/ 15 февраля 2012

Я много читал о том, что Node.js быстр и способен справляться с большими объемами нагрузки.У кого-нибудь есть реальные доказательства этого против других фреймворков, в частности .Net?Большинство статей, которые я прочитал, являются анекдотическими или не имеют сравнения с .Net.

Спасибо

Ответы [ 5 ]

362 голосов
/ 16 июня 2012

Быть FAST и обрабатывать партии LOAD - это две разные вещи.Сервер, который действительно FAST при обслуживании одного запроса в секунду, может полностью работать, если вы отправите ему 500 запросов в секунду (при LOAD ).

Вы также должны учитыватьстатические (и кэшированные) и динамические страницы.Если вы беспокоитесь о статических страницах, то IIS, вероятно, превзойдет узел, потому что IIS использует кэширование в режиме ядра, что означает, что запросы, запрашивающие статическую страницу, даже не собираются выходить из ядра.

Я предполагаю, что вы ищете сравнение между ASP.NET и узлом.В этой битве, после того, как все будет скомпилировано / интерпретировано, вы, вероятно, будете довольно близки по производительности.Может быть .NET немного FASTER или, может быть, узел немного FASTER , но он, вероятно, достаточно близко, чтобы вам было все равно.Я бы поставил на .NET, но я точно не знаю.

Место, где этот узел действительно убедителен, - это обработка LOAD .Вот где технологии действительно отличаются.ASP.NET выделяет поток для каждого запроса из своего пула потоков, и после того, как ASP.NET исчерпал все доступные запросы потоков начинают поступать в очередь.Если вы обслуживаете приложения «Hello World», такие как пример @shankar, то это может не иметь большого значения, потому что потоки не будут блокироваться, и вы сможете обрабатывать множество запросов перед вами.закончились темы.Проблема с моделью ASP.NET возникает, когда вы начинаете делать запросы ввода-вывода, которые блокируют поток (обращение к БД, выполнение http-запроса к службе, чтение файла с диска).Эти запросы на блокировку означают, что ваш ценный поток из пула потоков ничего не делает.Чем больше у вас блокировок, тем меньше LOAD будет работать ваше приложение ASP.NET.

Чтобы предотвратить эту блокировку, вы используете порты завершения ввода / вывода, которые не требуют удержания потока, пока вы ожидаете ответа.ASP.NET поддерживает это, но, к сожалению, многие из распространенных фреймворков / библиотек в .NET НЕ.Например, ADO.NET поддерживает порты завершения ввода / вывода, но Entity Framework их не использует.Таким образом, вы можете создать приложение ASP.NET, которое является чисто асинхронным и обрабатывает большую нагрузку, но большинство людей этого не делают, потому что это не так просто, как создать синхронное приложение, и вы не сможете использовать некоторые из ваших любимых частейфреймворка (например, linq для сущностей).

Проблема в том, что ASP.NET (и .NET Framework) были созданы для того, чтобы не думать об асинхронном вводе / выводе..NET не волнует, пишете ли вы синхронный или асинхронный код, поэтому решение за этим должен принять разработчик.Частично это связано с тем, что многопоточность и программирование с асинхронными операциями считались «сложными», и .NET хотел порадовать всех (новичков и экспертов).Это стало еще сложнее, потому что .NET закончила с 3-4 различными шаблонами для выполнения асинхронного..NET 4.5 пытается вернуться и модернизировать платформу .NET, чтобы создать самоуверенную модель асинхронного ввода-вывода, но может пройти некоторое время, пока фреймворки, о которых вы заботитесь, фактически ее поддержат.

Разработчики узла нас другой стороны, сделал взвешенный выбор, что ВСЕ ввод / вывод должен быть асинхронным.Благодаря этому решению разработчики узлов также смогли принять решение, что каждый экземпляр узла будет однопоточным, чтобы минимизировать переключение потоков, и что один поток будет просто выполнять код, который был поставлен в очередь.Это может быть новый запрос, это может быть обратный вызов из запроса БД, это может быть обратный вызов из запроса http rest, который вы сделали.Узел пытается максимизировать эффективность процессора, устраняя переключение контекста потока.Поскольку узел сделал этот выборный выбор, что ALL I / O является асинхронным, это также означает, что все его фреймворки / дополнения поддерживают этот выбор.Проще писать приложения, которые на 100% асинхронны в узле (потому что узел заставляет вас писать приложения, которые являются асинхронными).

Опять же, у меня нет точных цифр, которые можно было бы так или иначе доказать, но я думаю, что node выиграет конкурс LOAD для типичного веб-приложения.Сильно оптимизированное (100% асинхронное) приложение .NET может дать эквивалентное приложение node.js за свои деньги, но если вы взяли среднее значение всех .NET и всех приложений для узлов, то в среднем узел, вероятно, обрабатывает большеЗАГРУЗИТЬ.

Надеюсь, что поможет.

49 голосов
/ 17 мая 2012

Я провел элементарный тест производительности между nodejs и IIS. IIS примерно в 2,5 раза быстрее, чем nodejs, когда выдаете «привет, мир!». код ниже.

мое оборудование: Dell Latitude E6510, Core i5 (двухъядерный), 8 ГБ ОЗУ, 64-разрядная ОС Windows 7 Enterprise

узел сервера

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>

моя собственная тестовая программа, использующая параллельную библиотеку задач:

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

}
}

и результаты:

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

вывод: IIS быстрее, чем nodejs, примерно в 2,5 раза (в Windows). Это очень элементарный тест, и ни в коем случае не окончательный. Но я считаю, что это хорошая отправная точка. Nodejs, вероятно, быстрее на других веб-серверах, на других платформах, но в Windows IIS является победителем. Разработчики, желающие преобразовать свои ASP.NET MVC в nodejs, должны сделать паузу и дважды подумать, прежде чем продолжить.

Обновлено (17.05.2012) Tomcat (на окнах), кажется, побеждает руки IIS, примерно в 3 раза быстрее, чем IIS при создании статического html.

1021 * кот *

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

Результаты кота

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

обновленный вывод: я запускал тестовую программу несколько раз. Tomcat, по-видимому, является самым быстрым сервером в представлении STATIC HTML в WINDOWS.

Обновлено (18.05.2012) Ранее у меня было 100 000 запросов с 10 000 одновременных запросов. Я увеличил его до 1 000 000 и 100 000 одновременных запросов. IIS выходит как кричащий победитель, с Nodejs, обличающим худшее. Я привел в таблицу результаты ниже:

NodeJS vs IIS vs Tomcat serving STATIC HTML on WINDOWS.

17 голосов
/ 07 сентября 2014

NIO-серверы (Node.js и т. Д.), Как правило, работают быстрее, чем BIO-серверы. (IIS и т. Д.). Чтобы поддержать мое утверждение, TechEmpower - компания, специализирующаяся на тестах веб-фреймворка . Они очень открыты и имеют стандартный способ тестирования всех фреймворков.

Тесты 9-го тура в настоящее время самые последние (май 2014 г.). Было протестировано много разновидностей IIS, но Aspnet-Stripped, похоже, самый быстрый вариант IIS.

Вот результаты ответов в секунду (чем выше, тем лучше):

  • Сериализация JSON
    • nodejs: 228,887
    • без использования aspnet: 105,272
  • Одиночный запрос
    • nodejs-mysql: 88,597
    • aspnet-stripped-raw: 47,066
  • Несколько запросов
    • nodejs-mysql: 8,878
    • aspnet-stripped-raw: 3,915
  • Простой текст
    • nodejs: 289,578
    • без использования aspnet: 109,136

Во всех случаях Node.js имеет тенденцию быть в 2 раза быстрее, чем IIS.

11 голосов
/ 15 февраля 2012

Я должен согласиться с Маркусом Гранстромом: сценарий здесь очень важен.

Если честно, звучит так, будто вы принимаете архитектурное решение. Мой совет - изолировать проблемные области и сделать «пирог» между любыми стеками, которые вы рассматриваете.

В конце дня вы несете ответственность за решение, и я не думаю, что оправдание «Какой-то парень в Stackoverflow показал мне статью, в которой говорилось, что все будет хорошо» Порежу его твоим боссом.

1 голос
/ 23 августа 2013

Основное отличие, которое я вижу, состоит в том, что узел .js является динамическим языком программирования (проверка типов), поэтому типы должны быть получены во время выполнения. Языки со строгой типизацией, такие как C # .NET, теоретически имеют гораздо больший потенциал в борьбе с Node .js (и PHP и т. Д.), Особенно там, где требуются дорогостоящие вычисления. Между прочим, .NET должен иметь лучшее внутреннее взаимодействие с C / C ++, чем узел .js.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...