Неожиданный результат теста node.js против ASP.NET Core

177

Я делаю быстрый стресс-тест на двух (вроде) проектах Hello World, написанных на и , Оба они работают в производственном режиме и без подключенного к ним регистратора. Результат потрясающий! Ядро ASP.NET превосходит приложение node.js даже после выполнения некоторой дополнительной работы, тогда как приложение node.js просто отображает представление.

Приложение 1: http://localhost:3000/nodejs node.js

Использование : node.js, экспресс и движок рендеринга vash.

приложение nodejs

Код в этой конечной точке

router.get('/', function(req, res, next) {
  var vm = {
    title: 'Express',
    time: new Date()
  }
  res.render('index', vm);
});

Как видите, он ничего не делает, кроме отправки текущей даты через timeпеременную в представление.

Приложение 2: http://localhost:5000/aspnet-core asp.net core

Использование : ASP.NET Core, таргетинг на шаблоны по умолчаниюdnxcore50

Тем не менее, это приложение делает что-то другое, чем просто рендеринг страницы с датой на нем. Он генерирует 5 абзацев различных случайных текстов. Теоретически это должно сделать его немного тяжелее, чем приложение nodejs.

основное приложение asp.net

Вот метод действия, который рендерит эту страницу

[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
[Route("aspnet-core")]
public IActionResult Index()
{
    var sb = new StringBuilder(1024);
    GenerateParagraphs(5, sb);

    ViewData["Message"] = sb.ToString();
    return View();
}

Результат стресс-теста

Результат стресс-теста приложения Node.js

Обновление: по предложению Горги Косева

С помощью npm install -g recluster-cli && NODE_ENV=production recluster-cli app.js 8

тест nodejs 2

Результат стресс-теста ASP.NET Core App

основной стресс-тест asp.net

Не могу поверить своим глазам! Не может быть правдой, что в этом базовом тесте ядро ​​asp.net работает намного быстрее, чем nodejs. Конечно, это не единственный показатель, используемый для измерения производительности между этими двумя веб-технологиями, но мне интересно, что я делаю неправильно на стороне node.js? ,

Будучи профессиональным разработчиком asp.net и желая адаптировать node.js в личных проектах, это отчасти отталкивает меня, поскольку я немного параноидален в отношении производительности. Я думал, что node.js быстрее, чем ядро ​​asp.net (в целом - как видно из различных других тестов), я просто хочу доказать это самому себе (чтобы поощрить себя в адаптации node.js).

Пожалуйста, ответьте в комментарии, если вы хотите, чтобы я включил больше фрагментов кода.

Обновление: распределение времени .NET Core приложения

Распределение времени приложения aspnetcore

Ответ сервера

HTTP/1.1 200 OK
Cache-Control: no-store,no-cache
Date: Fri, 12 May 2017 07:46:56 GMT
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Server: Kestrel
не определено
источник
52
«Я всегда думал, что node.js быстрее ядра asp.net» - мне интересно, почему вы так думаете? Я не видел каких-либо тестов, которые бы поддерживали это (основные причины, по которым я слышал о переходе на node.js, были «простота использования» и «более быстрое время разработки / итерации»)
UnholySheep
7
@UnholySheep Это все, что я слышал, приятель, я также слышал, что он «прост в использовании» и «быстрее развивается», как правило, от людей, которые никогда не работали в ASP.NET, особенно в VisualStudio. Я не хвастаюсь ни одной технологией - но я заметил эту модель.
не определено
3
Какой вопрос здесь? Если это правдоподобно: да, это так. techempower.com/benchmarks/… .... Также обновите ваш инструментарий Dnxcore50 устарел как минимум на год или два.
Томас,
2
@Tony с использованием модуля кластера NodeJs порождает работу нескольких рабочих и распределяет нагрузку на основной процесс, который прослушивает один процесс. Это просто избавляет от необходимости устанавливать несколько приложений на разных портах. Также, если nodeJs работает в режиме кластера, тогда должно быть одинаковое количество веб-приложений Asp.Net, работающих в IIS на портах diff и распределять нагрузку между ними через некоторый балансировщик нагрузки, тогда это будет правильное сравнение.
Vipresh
36
Node.js отлично подходит для многих вещей, но скорость обработки запросов не является одной из них. В чем он преуспевает, так это в качестве посредника для операций ввода-вывода из-за неблокирующего цикла обработки событий, который, когда Node был новым и блестящим, был большой проблемой. Конечно, с тех пор другие языки и фреймворки догнали, поэтому в .NET у нас есть Task Parallel Library и асинхронный ввод-вывод и async / await. В чем Node не преуспевает, так это связанные с процессором операции, такие как рендеринг страниц, потому что это однопоточный JavaScript.
Марк Рендл

Ответы:

188

Как уже упоминали многие другие, для сравнения не хватает контекста.
Во время его выпуска асинхронный подход к node.js был революционным. С тех пор другие языки и веб-фреймворки перенимают те подходы, которые они приняли.

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

Рассмотрим этот сервер node.js, который ждет 1 секунду, прежде чем ответить

const server = http.createServer((req, res) => {
  setTimeout(() => {
    res.statusCode = 200;
    res.end();
  }, 1000);
});

Теперь давайте добавим 100 одновременных соединений в течение 10 секунд. Таким образом, мы ожидаем около 1000 запросов.

$ wrk -t100 -c100 -d10s http://localhost:8000
Running 10s test @ http://localhost:8000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.01s    10.14ms   1.16s    99.57%
    Req/Sec     0.13      0.34     1.00     86.77%
  922 requests in 10.09s, 89.14KB read
Requests/sec:     91.34
Transfer/sec:      8.83KB

Как вы можете видеть, мы входим в стадион с 922 завершено.

Теперь рассмотрим следующий код asp.net, написанный так, как будто async / await еще не поддерживается, поэтому мы возвращаемся к эпохе запуска node.js.

app.Run((context) =>
{
    Thread.Sleep(1000);
    context.Response.StatusCode = 200;
    return Task.CompletedTask;
});

$ wrk -t100 -c100 -d10s http://localhost:5000
Running 10s test @ http://localhost:5000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.08s    74.62ms   1.15s   100.00%
    Req/Sec     0.00      0.00     0.00    100.00%
  62 requests in 10.07s, 5.57KB read
  Socket errors: connect 0, read 0, write 0, timeout 54
Requests/sec:      6.16
Transfer/sec:     566.51B

62! Здесь мы видим предел пула потоков. Настраивая его, мы можем получать больше одновременных запросов, но за счет большего количества ресурсов сервера.

Для этих рабочих нагрузок, связанных с вводом-выводом, движение, чтобы избежать блокирования потоков обработки, было настолько драматичным.

Теперь давайте перенесем это на сегодня, где это влияние распространилось по всей отрасли и позволит dotnet воспользоваться преимуществами своих улучшений.

app.Run(async (context) =>
{
    await Task.Delay(1000);
    context.Response.StatusCode = 200;
});

$ wrk -t100 -c100 -d10s http://localhost:5000
Running 10s test @ http://localhost:5000
  100 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.01s    19.84ms   1.16s    98.26%
    Req/Sec     0.12      0.32     1.00     88.06%
  921 requests in 10.09s, 82.75KB read
Requests/sec:     91.28
Transfer/sec:      8.20KB

Здесь никаких сюрпризов, теперь мы сопоставляем node.js.

Так что же все это значит?

Ваши впечатления о том, что node.js является «самым быстрым», пришли из эпохи, в которой мы больше не живем. Добавьте к этому, что никогда не было «быстрым» node / js / v8, а потому, что они прервали поток на запрос модель. Все остальные догоняют.

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

Отказ от ответственности: Весь написанный код и тесты выполняются на устаревшем MacBook Air сонным воскресным утром. Не стесняйтесь захватить код и попробовать его в Windows или настроить под свои нужды - https://github.com/csainty/nodejs-vs-aspnetcore

Крис Сэйнти
источник
35
NodeJ никогда не были уникальными, модель Thread for request также существовала в Asp.Net до появления nodejs. У всех методов, которые выполняли ввод-вывод, было 2 версии синхронных и асинхронных, предоставляемых платформой, их методы ASYNC заканчивались ключевым словом «Async» для например. methodNameAsync
Vipresh
Как например. Вы можете сослаться на эту статью, связанную с операциями с БД, начиная с 2008 года. Codedigest.com/Articles/ADO/…
Vipresh
4
«Подходы, которые они использовали в мейнстриме» - мало что уникально, они ставят проблему перед гораздо более широкой аудиторией. Доступность подхода и его воплощение в качестве основного принципа - две совершенно разные вещи.
Крис Сэйнти
4
Лучший ответ здесь. Период.
Нарвалекс
3
@ LeeBrindley Я не согласен, это не попытка продемонстрировать максимальную пропускную способность данного оборудования, это демонстрирует разницу между блокированием и неблокированием. Если вы хотите сравнения производительности, я ссылаюсь на techempower.
Крис Сейнти
14

Фреймворки Node, такие как Express и Koa, имеют ужасные накладные расходы. «Сырой» узел значительно быстрее.

Я не пробовал, но есть более новая платформа, которая очень близка к производительности «сырого» узла: https://github.com/aerojs/aero

(см. тест на этой странице)

обновление: вот некоторые цифры: https://github.com/blitzprog/webserver-benchmarks

Node:
    31336.78
    31940.29
Aero:
    29922.20
    27738.14
Restify:
    19403.99
    19744.61
Express:
    19020.79
    18937.67
Koa:
    16182.02
    16631.97
Koala:
    5806.04
    6111.47
Hapi:
    497.56
    500.00

Как видите, накладные расходы в самых популярных фреймворках node.js ОЧЕНЬ значительны!

smorgs
источник
5
для чего нужны цифры? Чем выше, тем лучше?
Ямисти