С момента появления серверных сред для JavaScript NodeJS стал безраздельно популярной средой выполнения. Node вместе со своим менеджером пакетов NPM в настоящее время широко используется для проектов, начиная от небольших побочных проектов для любителей и заканчивая системами корпоративного уровня с высоким трафиком. Большинство разработчиков не осмелились бросить вызов Node из-за его статуса по умолчанию в отрасли и обширной экосистемы разработки с открытым исходным кодом. Deno был первым крупным претендентом, но так и не прижился, вероятно, из-за отсутствия тесной совместимости между Node, пакетами NPM с открытым исходным кодом и CommonJS.

Несколько дней назад, 8 сентября 2023 года, новый претендент, Bun, официально объявил о стабильном выпуске своей среды выполнения и сопутствующих инструментов, включая NPM-совместимый менеджер пакетов, сборщик пакетов, API и многое другое. «Bun обещает целый ряд преимуществ, в основном связанных с производительностью и опытом разработчиков, а также строгими стандартами совместимости. Другими словами, Bun выглядит как замена Node-приложениям, которая улучшает все, что касается опыта разработки JS-приложений и их производительности.

Как человек, работающий в основном над бессерверными приложениями, основанными на функциях, я сразу же задал вопрос: все это звучит великолепно, но могу ли я на самом деле это использовать? Меня это особенно интересовало, потому что Lambda оптимизировала свой сервис для NodeJS, так как же Бан будет справедлив, если у него нет официальной поддержки?Чтобы выяснить это, я разработал набор тестов для его тестирования. с целью ответить на мой вопрос.

Тесты

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

Общая производительность обработки

Бан утверждает, что может обрабатывать логику в 3–4 раза быстрее, чем NodeJS. Хотя многие приложения могут быть более привязаны к операциям ввода-вывода (запросы к базе данных, сетевые вызовы, чтение/запись в файловой системе и т. д.), этот тип общего улучшения, если он корректен, помогает каждой системе, особенно тем, у которых нагрузка на процессор и память ограничена. связанные рабочие нагрузки. Поэтому я хотел посмотреть, будут ли заявления Бана о чистой производительности применимы к бессерверной среде.

Тест: сгенерируйте и затем отсортируйте (с помощью встроенного метода Array.sort) 100 тысяч случайных чисел 10 раз подряд.

CRUD API

Тестирование рабочих нагрузок с интенсивным использованием ЦП интересно, но оно, вероятно, преувеличит реальные преимущества Bun, поскольку реальность такова, что лямбда-подобные среды очень часто используются для гораздо более простых приложений, которые больше связаны с вводом-выводом (сеть, файловая система и т.д.). Очень распространенный шаблон — совместное использование API Gateway, Lambda и DynamoDB для создания простых API CRUD, в которых вычисления просты. Я хотел протестировать эти более реальные сценарии, чтобы увидеть, сможет ли Bun по-прежнему обеспечивать преимущества даже при отсутствии тяжелой логики, связанной с процессором.

Тест: реализовать функцию обновления CRUD, которая проверяет входные данные, извлекает объект из DynamoDB, мелко объединяет запрошенные изменения с существующим объектом и помещает его обратно в DynamoDB.

Время холодного старта

Бессерверные функции, как правило, страдают от так называемой проблемы «холодного запуска». Функции AWS Lambda выполняются в контейнерной среде, время работы каждого контейнера обычно составляет 10–30 минут. Когда поступает запрос, а ни один контейнер не запущен и не доступен, Lambda запустит новый контейнер для обработки запроса, и это время запуска — это время холодного запуска, о котором мы говорим. Официально поддерживаемые среды выполнения, такие как NodeJS, обычно более оптимизированы для быстрого запуска, поэтому главный вопрос, на который нужно ответить, заключается в том, как будет сравниваться Bun, неоптимизированная среда выполнения?

Тест: функция Hello world с намеренно вызванным холодным запуском.

Конфигурация среды

Для этих тестов использовалась следующая конфигурация:

  • Функция REST API Gateway-to-Lambda (время ответа измеряется API-шлюзом для получения полного сквозного объема)
  • Память 1024 МБ для лямбда-функций
  • Архитектура x86_64 на Amazon Linux 2 для Bun
  • Базовая конфигурация среды выполнения на архитектуре x86_64 для Node.js 18.x
  • Обеспеченный параллелизм 5 (кроме теста холодного запуска)

Общие результаты испытаний обработки

Этот тест запускался 1000 раз для каждой среды выполнения, при этом данные о времени ответа собирались на стороне сервера и собирались в CloudWatch и X-Ray.

Узел

  • Среднее время ответа: 3736 мс
  • Минимальное время отклика: 3391 мс
  • Максимальное время отклика: 4580 мс
  • p95 Время отклика: 3989 мс
  • p99 Время отклика: 4404 мс

булочка

  • Среднее время ответа: 1836 мс (-50,9%)
  • Минимальное время отклика: 1564 мс (-53,9%)
  • Максимальное время отклика: 3571 мс (-22,0%)
  • Время отклика p95: 2027 мс (-49,2%)
  • Время отклика p99: 2117 мс (-51,9%)

Результаты тестирования CRUD API

Этот тест запускался 1000 раз для каждой среды выполнения, при этом данные о времени ответа собирались на стороне сервера и собирались в CloudWatch и X-Ray.

Узел

  • Среднее время ответа: 24 мс
  • Минимальное время отклика: 17 мс
  • Максимальное время отклика: 135 мс
  • p95 Время отклика: 29 мс
  • p99 Время отклика: 51 мс

булочка

  • Среднее время ответа: 25 мс (+4,2%)
  • Минимальное время отклика: 16 мс (-5,9%)
  • Максимальное время отклика: 157 мс (+16,3%)
  • p95 Время отклика: 33 мс (+13,8%)
  • p99 Время отклика: 44 мс (-13,7%)

Время холодного старта

Этот тест запускался только 10 раз для каждой среды выполнения, поскольку не существует хорошего способа автоматизировать принудительный холодный запуск в нагрузочном тесте. Обратите внимание, что приведенные здесь результаты отражают полное время ответа, а не только время инициализации.

Узел

  • Среднее время ответа: 302 мс
  • Минимальное время отклика: 252 мс
  • Максимальное время отклика: 361 мс
  • p95 Время отклика: 312 мс
  • p99 Время отклика: 361 мс

булочка

  • Среднее время ответа: 775 мс (+156%)
  • Минимальное время отклика: 717 мс (+184%)
  • Максимальное время отклика: 1382 мс (+282%)
  • Время отклика p95: 1174 мс (+276%)
  • p99 Время отклика: 1382 мс (+282%)

Интерпретация результатов

К моему удивлению, несмотря на то, что Node был специально оптимизирован для Lambda, а официальный уровень Bun Lambda Layer был недостаточно протестирован (и, следовательно, не оптимизирован), Bun удалось выйти вперед в измеримых и значительных аспектах для задач, связанных с процессором. Он также идеально подходил для более простых задач, связанных с вводом-выводом, а это означает, что вы, как минимум, вряд ли увидите снижение производительности при использовании Bun. Я думаю, если бы AWS Lambda добавила Bun в качестве официальной среды выполнения, мы бы увидели, что Bun работает как минимум немного лучше, чем Node, если не со значительными улучшениями. А если вы используете свою логику с помощью таких фреймворков и библиотек, как Express, Nest, Apollo или NextJS, я не удивлюсь, если вы увидите постоянно более высокую производительность (это то, что я хотел бы протестировать дальше).

Готов ли он к производству? Что ж, я бы пока не стал делать такой вывод, потому что на пути к слою Bun Lambda я столкнулся с некоторыми трудностями, и на данный момент он не особенно проверен в боевых условиях. Кроме того, некоторые API-интерфейсы NodeJS еще не совместимы с Bun, а сам Bun все еще очень новый, а это означает, что мы еще не знаем всех его особенностей. Однако эти проблемы решаемы, и эти тесты показывают, что при некоторых усилиях существует реальный потенциал для того, чтобы это была законная среда выполнения для разработки производственных бессерверных приложений.

Решение проблем с холодным запуском

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

  1. Официальное решение AWS для обеспечения параллелизма, которое поддерживает заданное количество контейнеров всегда теплыми за определенную плату. В зависимости от нагрузки вашего приложения этот подход может быть либо очень разумным, либо может оказаться более дорогим, чем он того стоит.
  2. Специальное решение для подогрева, которое время от времени проверяет вашу функцию Lambda, чтобы гарантировать постоянную доступность нескольких контейнеров. Это хорошее решение для приложений с низкой пропускной способностью, поскольку оно дешевое и позволяет держать контейнер готовым к использованию, когда он вам понадобится.

Преимущества производительности

В обычных случаях использования приложений простая замена NodeJS на Bun может немного улучшить задержку, придав вашим приложениям более быстрый вид. Чем больше ваше приложение выполняет сами вычисления, тем больше преимуществ вы увидите, поэтому это действительно будет зависеть от ваших конкретных вариантов использования. Тем не менее, в сочетании со стратегией холодного запуска, похоже, что Bun будет, по крайней мере, соответствовать Node, предлагая при этом все другие преимущества опыта разработки.

Экономическая выгода

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

Еще одно предостережение, о котором следует помнить: использование встроенной среды выполнения Node означает, что вам не будут выставлены счета за затраты на инициализацию (холодный запуск). С другой стороны, с вас взимается плата за инициализацию контейнеров Lambda для Bun, поэтому помимо борьбы с проблемами холодного запуска из соображений производительности вы, вероятно, захотите также уменьшить их для экономии средств.

Последние мысли

Я очень скептически относился к Bun в целом и особенно с точки зрения возможности его использования в рабочем процессе бессерверных приложений. Я был приятно удивлен, когда эти результаты развеяли этот скептицизм. Хотя я пока не буду лично использовать Bun для разработки Lambda из-за его новизны, я буду пристально следить за ним по мере развития его экосистемы и по мере дальнейшего усовершенствования и оптимизации инструментов для Bun on Lambda.

Кстати, в этой статье не обсуждался опыт разработки Bun, но суть в том, что это был освежающий опыт с чрезвычайно быстрой установкой и сборкой пакетов, а также эффективной встроенной поддержкой локального тестирования функций Lambda - что-то другое. более болезненный и требует дополнительных инструментов от AWS SAM. Я думаю, что, будучи более зрелым, у Bun есть реальный шанс обогнать Node в качестве среды выполнения по умолчанию для разработки JavaScript и TypeScript, и я лично буду за это болеть. Кроме того, AWS Lambda, если вы читаете эту статью, рассмотрите возможность поддержки Bun в качестве встроенной среды выполнения для Lambda.