Go, Python и TypeScript - могут ли они заменить Java для внутренней разработки?

По состоянию на 2020 год наиболее часто используемым языком программирования для создания серверной части веб-приложений по-прежнему является Java. Однако Java также известна своим медленным запуском и огромным объемом памяти. Эти накладные расходы особенно дороги в микросервисной архитектуре, так как вам придется снова оплачивать их за каждую услугу. Эту проблему пытаются решить множество фреймворков и технологий Java, однако на данный момент ни одна из них не преуспевает (подробности по этой теме см. В моем рассказе Какую платформу микросервисов Java следует выбрать в 2020 году). Поэтому в этой истории я хотел проверить, что другие языки программирования могут предложить для реализации высокопроизводительных микросервисных приложений.

Кандидаты

Go

Go - это статически типизированный компилируемый язык программирования, представленный Google в 2007 году. Хотя синтаксически он похож на C, он предоставляет такие функции, как безопасность памяти, сборка мусора, структурная типизация и параллелизм. Go обещает ответить на критику на других языках, но сохранит их полезные характеристики. Он должен быть таким же производительным, как C ++, но в то же время читабельным, как Python, и таким же удобным, как JavaScript.

Система параллелизма Go, основанная на Goroutines, является прочной базой для разработки параллельных приложений. Поэтому он уже активно используется для создания сетевых инструментов (в первую очередь Kubernetes), но также набирает обороты в качестве внутреннего языка для веб-приложений. Стандартная библиотека уже предоставляет все, что вам нужно для реализации Rest-Backend.

JavaScript / Typescript с Express.js

JavaScript - это динамически типизированный язык программирования, основанный на прототипах. Он был представлен в 1995 году как язык сценариев внешнего интерфейса, работающий внутри веб-браузера. С тех пор он стал одним из самых популярных языков программирования и, по крайней мере, с момента появления Node.js в 2009 году, он все чаще используется как серверный язык. Express.js - это платформа приложений, предназначенная для создания веб-приложений и API. Это де-факто стандартный серверный фреймворк для Node.js. В TypeScript Microsoft представила надмножество JavaScript, добавив в язык статическую типизацию.

Node.js работает с однопоточным циклом обработки событий, используя неблокирующие вызовы ввода-вывода. Это позволяет поддерживать тысячи одновременных подключений без дополнительных затрат на поддержку нескольких потоков. Таким образом, разработчик может реализовать высокопроизводительные и высокопроизводительные веб-приложения.

Python

Python - это интерпретируемый язык программирования общего назначения, впервые выпущенный в 1991 году. Он постоянно входит в десятку самых популярных языков программирования в Индексе сообщества программистов TIOBE и широко используется в проектах искусственного интеллекта и машинного обучения с помощью таких библиотек, как TensorFlow или Scikit. Python прост в использовании, мощен и универсален. Его удобочитаемость делает его отличным первым языком программирования - он позволяет думать как программист и не тратить время на запутанный синтаксис.

В интерфейсе шлюза веб-сервера (WSGI) был определен стандартный API для разработки веб-приложений, и на его основе развились несколько фреймворков веб-приложений, таких как Django и Falcon.

Джава

Я сравню их с тремя разновидностями Java: стандартным приложением Spring и приложением Micronaut, использующим традиционную JVM, и приложением Micronaut, использующим собственный образ с GraalVM. Ознакомьтесь с моей историей Какую платформу микросервисов Java следует выбрать в 2020 году для получения более подробной информации.

Сравнение фреймворков

Чтобы сравнить упомянутые языки и фреймворки, я реализовал простое приложение, использующее каждый из них. Пример приложения состоит из интерфейса REST для создания, чтения, обновления и удаления объектов и коннектора реляционной базы данных, который сохраняет эти объекты в таблице. Затем я запускал каждое приложение как образ Docker и сравнивал их производительность на трех ключевых этапах:

  • Насколько легко было реализовать пример приложения? Чтобы реализовать приложения, мне пришлось проверять документацию, а также искать информацию на таких платформах, как Stack Overflow.
  • Сколько времени нужно на компиляцию приложения? Я измерил время, необходимое для выполнения чистой сборки, включая создание образа Docker.
  • Сколько времени нужно, чтобы запустить приложение? Здесь я измерил время между запуском docker up и правильным ответом приложения на первый HTTP-запрос. Кроме того, я измерил объем памяти, занимаемый неактивными приложениями сразу после загрузки.
  • Нагрузка: сколько запросов приложение может обработать при просмотре? Я использовал JMeter для выполнения нагрузочного тестирования и протестировал приложение с 25% запросов, выполняющих запись в базу данных, и 75% из них выполняли только чтение базы данных. Затем я измерил объем памяти, занимаемый приложением, при его максимальной производительности.

Я выполнил все измерения на стандартной виртуальной машине Azure D2s v3 с двумя виртуальными процессорами и 8 ГиБ памяти. Все реализации и результаты вы можете найти в моем репозитории Github.

Полученные результаты

Легкость развития

Поскольку у меня были только предыдущие знания об использовании Java, это немного несправедливое сравнение. Однако я полагаю, что даже для стороннего наблюдателя Java (и особенно Spring Framework) действительно предоставляет хорошую и понятную документацию, а также широкий спектр руководств, охватывающих все мыслимые аспекты. С другой стороны, кривая обучения Java более крутая по сравнению с более современными языками, и часто существует несколько стратегий для достижения одной и той же цели, что может быть сложно для неопытных разработчиков. Например, разные веб-стеки для Spring (MVC и WebFlux) во многом похожи, но когда вы этого не ожидаете, они ведут себя по-разному ...

Go легко начать, но сложно освоить. Есть хорошие руководства по запуску, но даже для решения основных проблем, таких как обработка ошибок, нет хорошей стандартной стратегии. Или, как выразился Сударака Джаятилака в своем рассказе Переосмысление обработки ошибок на Голанге:

У Голанга много преимуществ, этим объясняется его популярность. Но обработка ошибок в Go 1 не очень эффективна, нам приходится писать много подробных неудобных кодов в повседневной разработке.

Сообщество Go (пока) не такое большое и опытное, как сообщества Java и JavaScript, поэтому получить помощь немного сложнее. Однако дайте ему еще несколько лет, и они будут там.

JavaScript был создан, чтобы обеспечить простую кривую обучения, позволяющую даже неопытным программистам очень быстро начать писать код. Однако за это приходится платить. Как только вы вникаете в подробности, все быстро становится странным. Существует множество JavaScript WTF (например, проверьте javascriptwtf.com), показывающих, как иногда ведет себя странный JavaScript. Типовые скрипты и особенно линтеры могут уберечь вас от наиболее распространенных ошибок, но в какой-то момент JavaScript сведет вас с ума ...

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

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

Компиляция

Время компиляции сильно различается между выбранными языками, так как некоторые из них должны быть скомпилированы в машинный код, а другие интерпретируются или компилируются точно в срок. Безусловно, самым быстрым языком здесь был Python, поскольку он не компилировался, и для создания образа докера требовалось всего около 1,5 секунд. Go невероятно быстр для компилируемого языка, так как в среднем для создания приложения требовалось около 4 секунд. Java занял немного больше времени: 17 секунд для Spring и 24 секунды для приложения Micronaut.

Меня удивил Машинопись. Несмотря на то, что для этого нужно всего лишь преобразовать программу в JavaScript, в среднем на это ушло 77 секунд. Это в три раза больше, чем вся компиляция Java! Я не понимаю, что компилятор машинописного текста делает все это время, напишите мне ответ, если вы знаете ... Если вы пишете код JavaScript напрямую, компиляция не требуется, однако из-за файловой структуры в моем случае это Создание образа докера заняло немного больше времени по сравнению с python.

А еще есть собственный образ Грааля… В среднем на его создание ушло более 7,5 минут (!). Это делает невозможными быстрые циклы развития.

Запускать

Как и ожидалось, Java был самым медленным языком для запуска и имел самый большой объем памяти. Spring использовал в среднем 9,7 секунды, Micronaut был на 6 секунд немного быстрее. Обоим потребовалось около 150 МБ памяти сразу после запуска. При использовании Graal все становится намного эффективнее, запуск занял всего около трех секунд, а использование памяти составило 35 МБ.

Это выводит Java на уровень других языков. Go запускался быстрее всех (в среднем 2,8 секунды) и потреблял меньше всего ресурсов (всего 6 МБ). JavaScript / Typescript (3 секунды и 18 МБ), а также Python (3 секунды и 28 МБ с Falcon / 49 МБ с Django) были немного помедленнее.

Время выполнения

При полной загрузке все языки показали сопоставимую производительность. В конце концов, приложения большую часть времени ждали базу данных Postgres. Самым быстрым был Java с использованием Graal (15 с), а самым медленным - Typescript (22 с). Примечательное исключение: приложение Python, использующее Django, использовало более 70 секунд для выполнения той же работы. Я ожидаю, что это связано с неэффективным пулом соединений с базой данных в моем приложении. Однако мне не удалось настроить Django для эффективного использования такого пула соединений.

Однако объем памяти сильно отличался. Как и ожидалось, самой жадной оказалась Java (от 312 МБ для весны до 344 МБ для Micronaut в Graal). Go показал лучшую производительность при использовании только 30 МБ, за ним следуют Python (31 МБ при использовании Falcon, 63 МБ Django) и JavaScript (101 МБ ).

Выводы

Предвзятое мнение о большом использовании памяти Javas и медленном запуске оказывается верным. Даже для этого смехотворно маленького приложения реализации Java требовалось уже 300 МБ памяти и до девяти секунд для загрузки. Как было показано в моем последнем рассказе, GraalVM может решить эту проблему лишь частично.

С точки зрения производительности Go - явный победитель в этом сравнении. Он обеспечивает быструю компиляцию и запуск, а также чрезвычайно малый объем памяти. Однако, что касается простоты разработки, Go все еще может улучшиться. Особенно рассматривается обработка ошибок, поскольку она предоставляет несколько решений, но ни одно из них не решает проблему.

Python был быстрым, но для меня писать приложения было довольно сложно. Даже базовые функции, такие как пул соединений с базой данных, в Python затруднены. Если вам не нужны его AI или математические библиотеки, я не вижу смысла использовать его в качестве внутреннего языка. По производительности он хороший, но до Go не дотягивает.

Для меня TypeScript (и, в меньшей степени, JavaScript) является победителем с точки зрения простоты разработки. Огромное количество библиотек, простая кривая обучения и документация, но особенно активное и чрезвычайно полезное сообщество делают разработку на TypeScript легкой задачей. По производительности он уступает Go или Python, но все же легко превосходит Java. И в качестве дополнительного бонуса вы можете использовать один и тот же язык во внешней и внутренней части, что значительно упрощает разработку приложений.

Ресурсы