[Из песочницы] Dart vs Node.js: сравниваем производительность на реализациях HTTP сервера

-wrtv2m7hogm77rf9uqawk3jtwy.png

Всем доброго времени суток!

В этом году с выходом Flutter — фреймворка для кроссплатформенной разработки приложений наметился подъем хайпа по языку Dart. Как и любой перфекционист прокрастинирующий от скуки лентяй я задумался о сравнении производительности серверной реализации виртуальной машины Dart с ее потенциальным антагонистом в лице Node.js. Скажу сразу, что во мне теплилась надежда что Dart победит, а я обрету святой грааль дарующий мне превосходство над потенциальными конкурентами на ближайшие пару тройку пятилеток, но реальность оказалось немного иной…


Инструментарий


  • Тестовая машина: Core I7, SSD, 12GB ОЗУ (любезно предоставленная моим прошлым работодателем)
  • Нагрузочное тестирование: k6.io (кстати очень интересный по своей архитектуре фреймворк)

Организация кода приложений

Исходники

Тут я особо решил не заморачиваться и решил следовать рекомендациям, которые вычитывал в свое время на Хабре. В частности:


  • Добавил полезную нагрузку в качестве работы по генерации рандомных данных (рандомных, чтобы исключить потенциальное кеширование результатов)
    class Human {
        constructor (id, name, surname, age, gender) {
            this.id = id
            this.name = name
            this.surname = surname
            this.age = age
            this.gender = gender
        }
    }

  • Как в Dart так и в Node.js использовал варианты синхронной и асинхронной обработки запроса.
  • Применил варианты нативных решений и варианты решений на отраслевых фреймворках (aqueduct for dart и express for node.js)
  • Так как в ходе исследования удалось получить существенное ускорение работы Dart при использовании aqueduct, который запускает изоляты на каждом ядре, то для целей уравновешивания применил модуль cluster для node.js

Методика тестирования


  • запускал нагрузочные тесты с заданным числом запросов в секунду (500, 750) и ограничением на количество итераций теста (количество завершенных запросов)
  • как приложение так и тестирующий фреймворк были запущены на одной машине, соответственно стоит понимать, что все результаты являются относительными и могут быть сравнимы только друг с другом

Результаты


Native Dart


500 rps

b8c3a85945753cb42822113973114f9a.png


750 rps


  • http_reqs: 309.10154/s

Aqueduct framework for Dart


500 rps

a0b854bc111c723d68e20e3c488f8a78.png


750 rps

33ae4e74116eeab6d1f98ac075588d8c.png


Native Node.js


500 rps

6654bb3adb9d2a30b7e165e06fcd6772.png


750 rps

ea8bc6e55abf7e86167dd29c9975488d.png


Node Express with Cluster


500 rps

36413ce00e080236ac2f1142dd218b57.png


750 rps

9ec1cd0c1950235acb07de37f29e8a97.png


Выводы


  • Конечно многое зависит от того как Вы реализовали логику приложения, я не особо уверен, что мой код является оптимальным как в случае dart так и node.js
    • В частности функцию генерации массива можно было вывести в отдельный worker поток с асинхронным выводом, в моем случае это не было реализовано, поэтому здесь на самом деле не использована вся мошь асинхронщины
    • Как в Dart так и в Node.js вывод можно было организовать через поток
    • Поэтому здесь еще много места как для исследования производительности, так и для оптимизаций
  • Dart в нативной реализации хендлеров показал эпичейский фейл, тем не менее при реализации через фреймворк показал впечатляющие результаты, согласно которым виртуальная машина Dart уже сейчас может составить конкуренцию Node.js
  • На сколько я знаю, в оптимизацию работы V8 вложено колоссальное количество человеко-часов труда, я более чем уверен, что в виртуальную машину Dart вложено гораздо меньше времени. Поэтому у второй возможно есть достаточно больший потенциал для оптимизаций перед V8

© Habrahabr.ru