Node.js против производительности сети.

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

Спасибо

Ответы

Ответ 1

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

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

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

Место, в котором node действительно привлекательно, предназначено для обработки 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 хотел сделать всех счастливыми (noobs и эксперты). Это стало еще труднее, потому что .NET закончил с 3-4 различными шаблонами для выполнения async..NET 4.5 пытается вернуться и модернизировать платформу .NET, чтобы иметь модель с умеренной оценкой вокруг асинхронного ввода-вывода, но может потребоваться некоторое время, пока инфраструктура, которую вы заботитесь, фактически не поддержит ее.

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

Опять же, у меня нет каких-либо трудных чисел, чтобы доказать, так или иначе, но я думаю, что node выиграет конкурс LOAD для типичного веб-приложения. Высокооптимизированное (100% асинхронное) приложение .NET может дать эквивалентное приложение node.js запустить за это деньги, но если вы в среднем усреднили все .NET и все приложения node там, в среднем node, вероятно, обрабатывает больше LOAD.

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

Ответ 2

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

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

node сервер

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, должны сделать паузу и подумать дважды, прежде чем продолжить.

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

кот

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

Результаты 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

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

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

NodeJS vs IIS vs Tomcat serving STATIC HTML on WINDOWS.

Ответ 3

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

Честно говоря, это звучит так, как будто вы принимаете большое архитектурное решение. Мой совет состоял бы в том, чтобы изолировать области, вызывающие озабоченность, и сделать "испечь" между любыми стеками, которые вы рассматриваете.

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

Ответ 4

Серверы NIO (nodejs и т.д.) имеют тенденцию быть быстрее, чем серверы BIO. (IIS и т.д.). Чтобы подтвердить свое требование,

Techempower - это компания, специализирующаяся на тестировании веб-фреймворков. Они очень открыты и имеют стандартный способ тестирования всех фреймворков. Проверка http://www.techempower.com/benchmarks/

В настоящее время последние 9 тестов являются последними. Существует много тестов IIS, но Aspnet-stripped, по-видимому, является самым быстрым вариантом IIS. Вот результаты: Json Сериализация: NodeJS: 228 887, aspnet-stripped: 105,272 Единый запрос: nodejs-mysql: 88,597, aspnet-stripped-raw: 47,066 Несколько запросов: nodejs-mysql: 8,878, aspnet-stripped-raw: 3,915 Обычный текст: nodejs: 289 578, aspnet-stripped: 109,136

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

Ответ 5

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