Неожиданный результат теста node.js vs ASP.NET Core
Я делаю быстрый стресс-тест на двух (добрых) проектах hello world, написанных на node.js и asp.net-core. Оба они работают в режиме производства и без подключенного к ним регистратора. Результат поражает! Ядро 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 ОЧЕНЬ значительны!