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

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

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

Использование: node.js, express и vash engine.

nodejs app

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

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 core app

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

[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 test 2

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

результат стресс-теста asp.net

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

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

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

Update: Распределение времени приложения .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

Ответ 1

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

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

Рассмотрим этот сервер 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! Здесь мы видим предел потока. Подстраивая его, мы могли бы получать больше одновременных запросов, но за счет большего количества ресурсов сервера.

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

Теперь давайте доведем его до сегодняшнего дня, где это влияние распространилось по отрасли и позволило 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

Ответ 2

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

Масштабирование - совсем другое дело, и именно здесь Node выделяется из-за асинхронного характера. Он не блокирует основной поток и позволяет сразу нескольким вещам. ASP.NET делает это также (используя async/await), как и многие другие фреймворки. Это не совсем роман, действительно.

Node претензия к славе никогда не была скоростью, она масштабировалась. Вы могли бы делать что-то с этим дешево и быстро, и это, во всяком случае, масштабировалось бы намного лучше, чем популярные фреймворки в то время, а именно Ruby on Rails.

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

Ответ 3

Node У рамок, таких как Express и Koa, страшные накладные расходы. "Raw" Node значительно быстрее.

Я не пробовал, но есть более новая структура, которая очень близка к производительности "Raw" Node: https://github.com/aerojs/aero

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

update: Вот несколько цифр: 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 ОЧЕНЬ значительны!