На первый взгляд, выбор правильного Java-рантайма для вашего проекта на Spring Boot может показаться тривиальным. В конце концов, все популярные рантаймы основываются на коде OpenJDK и предлагают одинаковые программные интерфейсы.

Но не все рантаймы реализованы одинаково. В этой статье мы обсудим различные показатели, которые могут повлиять на ваше решение выбрать определенный дистрибутив Java для Spring Boot приложения.

Оригинал статьи написан на английском языке Aleksey Stukalov, который является Team Lead’ом проекта IntelliJ IDEA в компании JetBrains, и Catherine Edelveis, работающей Developer Advocate в компании BellSoft, в соавторстве.

От переводчика

На данный момент не существует русскоязычного ресурса посвященного разработке на Spring Boot. Или все таки существует?

Совсем недавно запустилось сообщество Spring АйО, в котором можно получить актуальные новости из мира Spring Boot, гайды и другие полезные материалы. Мы ждем всех, присоединяйтесь!

С точки зрения разработчика

Функциональная совместимость

Для большинства разработчиков не имеет большого значения, какой дистрибутив Java использовать, даже если они не используют Spring Boot или какой-либо другой фреймворк.

Почему? Секрет в Technology Compatibility Kit или TCK (англ. — Комплект технологической совместимости).

Сам по себе JDK это просто поверхность, скрывающая «под капотом» тонны различных спецификаций. Чтобы быть уверенным, что ваша реализация JDK может корректно исполнять Java-приложение, она проверяется огромным количеством тестов, входящих в TCK. Реализации, которые проходят все эти тесты получают маркировку «TCK-verified distribution» (англ. — дистрибутив, проверенный TCK), которая дает разработчикам полную уверенность в том, что их приложение будет вести себя одинаково со всеми другими реализациями Java, имеющими такую же маркировку.

В то же время, помимо гарантированного одинакового поведения вашего кода могут существовать другие особенности, о которых мы расскажем далее.

Поддержка инструментария

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

Прошли те времена, когда скачивать JDK c веб-сайта его разработчика было нормой. Сейчас установка предпочитаемой IDE обеспечивает наличие требуемого runtime Java. Если это IntelliJ IDEA, то в качестве JDK по умолчанию будет JetBrains Runtime, форк OpenJDK, предлагающий несколько улучшений относительно оригинала, таких как улучшенное переопределение классов (DCEVM) для бесшовной загрузки обновлений кода и наличие опционального JCEF (фреймворк для встраивания браузеров, основанных на движке Chromium). Несмотря на то, что эти улучшения могут быть востребованы не у всех команд разработки, встраивание JetBrains Runtime в инструменты в качестве среды по умолчанию делает ее одной из самых используемых среди Java-разработчиков.

Кроме того, вы можете скачивать различные JDK в один клик. Amazon Corretto, Azul Zulu, BellSoft Liberica JDK (стандартный или с JavaFX), Eclipse Temurin, GraalVM CE или Oracle GraalVM, IBM Semeru и SapMachine доступны к установке прямо из среды разработки и достаточно популярны среди разработчиков.

Специфика Spring Boot

Spring Boot предлагает удобное решение для оформления вашего приложения в контейнерный образ без необходимости составлять Dockerfile — buildpacks. Однако, для такой задачи могут быть использованы не все Java-рантаймы. Paketo buildpacks, используемый в Spring Boot, предлагает несколько дистрибутивов JDK в качестве основы для контейнерного образа. Выбор по умолчанию тут LibericaJDK, которая заодно является рантаймом, официально рекомендованным проектом Spring. Вы можете также использовать и другие JDK, но тут надо иметь в виду, что некоторые из них предлагают только релизы JDK, которые могут сделать потребление оперативной памяти контейнером значительнее чем с JRE.

Когда вы используете Paketo buildpacks, также важно выбирать того же разработчика JDK и для задач разработки. Даже несмотря на совместимость дистрибутивов по TCK, все равно можно получить проблемы с отладкой утечек памяти, производительности и другого рода при использовании различных JDK в разработке и продакшне.

С точки зрения DevOps

По мере приближения к развертыванию в продуктивном окружении, особенности архитектуры Spring Boot приложений требуют все больше внимания. Современные сервисы работают «в облаках», где стандартом де-факто стал Kubernetes (K8s) поэтому мы примем эту платформу за целевую.

Настройка параметров K8s

Развертывание приложений в облаке с Kubernetes является на самом деле наиболее простым, т.к. эта технология предлагает эффективные настройки и оркестрацию «из коробки».

Однако дополнительная настройка параметров может быть оправданной, особенно учитывая существенные требования Spring Boot к оперативной памяти. Рекомендации для увеличения производительности ваших Java-приложений в Kubernetes могут включать следующие пункты:

  • Установите лимиты CPU и RAM подов K8s на основании нагрузочного и стресс тестирований в режимах обычной работы и пиковых нагрузок.

  • Выберите подходящий сборщик мусора. Кроме популярных ParallelGC и G1GC новые версии Java включают и другие реализации GC, такие как ZGC и ShenandoahGC (позднее исключенный из Oracle Java), которые разработаны для обеспечения максимальной отзывчивости в условиях работы с большим количеством используемой оперативной памяти.

  • Используйте prob’ы для мониторинга состояния ваших подов и возможности оперативно реагировать на нештатные ситуации.

Использование JRE в контейнерах

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

Контейнеризированные приложения Spring Boot могут становиться достаточно тяжелы. Чтобы уменьшить их размер, вы можете использовать правильный базовый образ с JRE и легковесным дистрибутивом Linux, таким как Alpine или Alpaquita.

Таблица ниже отображает характеристики контейнерных образов для JDK 21, доступных на Docker Hub. Мы сравнили размеры сжатых образов JDK и JRE от различных поставщиков JDK с OS слоями на musl или glibc (бездистрибутивные образы не рассматривались, т.к. подходят не для всех случаев). Данные были собраны 23 апреля 2024г.

Все образы, кроме Liberica JDK и Red Hat OpenJDK, базируются на Alpine Linux (с musl) или Ubuntu (glibc). Образы Liberica JDK используют Alpaquita Linux, который на 100% совместим с Alpine, но имеет как musl так и glibc варианты. Образы Red Hat OpenJDK основаны на RHEL UBI 9.

Сборки Oracle Java недоступны на Docker Hub.

   

Liberica JDK  

Amazon Corretto  

Azul Zulu  

IBM Semeru Runtimes  

Eclipse Temurin  

Red Hat OpenJDK  

JDK + glibc  

85.63 MB  

212.66 MB  

191.89 MB  

260.52 MB  

197.87 MB  

148.5 MB  

JRE + glibc  

52.97 MB  

-*  

106.97 MB  

96.44 MB  

92.82 MB  

126.7 MB  

JDK + musl  

78.02 MB  

155.72 MB  

157.66 MB  

–  

167.05 MB  

–  

JRE + musl  

45.37 MB  

-*  

72.43 MB  

–  

62.5 MB  

–  

*Образы JRE для Amazon Corretto не доступны на Docker Hub, но есть в AWS (Amazon Web Services — облачный хостинг-сервис).  

Обновление до новейших версий Java 

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

Начиная с версии 3.х Spring Boot требует, как минимум, Java 17, а значит обновление версий Java первостепенно, если вы хотите использовать всю мощь новой версии любимого фреймворка.  

Однако, если обновление вам прямо сейчас не подходит, некоторые поставщики, такие как Oracle и BellSoft, предлагают решения, совместимые с версиями JVM 17 и JDK 8 (BellSoft также имеет подобное решение и для JDK 11). Это позволяет вашему приложению продолжать считать, что оно использует старую версию Java, на самом деле работая на новой. Что это значит для нас? Не надо обновлять Java или фреймворк и менять код (совсем или почти), чтобы получить улучшение отзывчивости и пропускной способности! 

Минимизация времени запуска

Сложным приложениям на Spring Boot может потребоваться несколько десятков секунд для запуска. Даже маленькому демонстрационному Spring Petclinic требуется от 5 до 7 секунд! Кроме того, Java-приложения потребляют больше ресурсов во время прогрева, чем во время обычной работы. Это приводит к следующим результатам:  

  • Повышенному расходу денег на дополнительные циклы CPU во время прогрева на больших экземплярах виртуальных машин.  

  • Разочарованию пользователей от больших задержек в отзывчивости.  

  • Невозможности использовать полный потенциал таких сервисов как AWS Lambdas.  

К счастью, Spring Boot 3 поддерживает два из наиболее эффективных решений для борьбы с тормозами прогрева — GraalVM Native Image и проект Coordinated Restore at Checkpoint (CRaC). Все, что вам нужно сделать — это выбрать поставщика Java, который поддерживает данный функционал.

Coordinated Restore at Checkpoint (CRaC) 

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

Spring Boot интегрируется с CRaC начиная с версии 3.2. На данный момент два поставщика OpenJDK предлагают сборки JDK с поддержкой CRaC: Azul и BellSoft. Разработчики Azul занимаются только JDK и полагаются на поддержку CRaC в Ubuntu. BellSoft предоставляет контейнер для CRaC-нутых образов, работающих на Alpaquita Linux и Liberica JDK их собственной разработки, благодаря чему вы можете использовать CRaC в контейнере Docker без изменений в JDK или Linux или дополнительной конфигурации приложений, кроме добавления зависимости от пакетов org.crac.  

Проект CRaC пока еще не верифицирован для TCK. Если вы ищете готовое к продуктиву решение, посмотрите на технологию Native Image.  

Native Image 

Технология Native Image позволяет разработчикам Java конвертировать свои приложения в статические бинарные образы при помощи ahead-of-time компиляции в предположении о замкнутости мира. Нативные образы запускаются практически мгновенно и могут производить впечатление меньшего потребления ресурсов за счет того, что они не включают JDK.  

Кроме Oracle, Native Image в состав своих JDK включают два поставщика Java:  

  • Mandrel от Red Hat, адаптированный для фреймворка Quarkus.  

  • Liberica Native Image Kit от BellSoft как компилятор для native-image по умолчанию в Spring buildpacks и рекомендован командой Spring. Он основан на GraalVM CE, но включает ParallelGC, который отсутствует в бесплатной редакции GraalVM Community Edition.  

С точки зрения SecOps

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

Использование ведомости основных программных материалов  

Software Bill of Materials (SBOM — англ. ведомость основных программных материалов) является неотъемлемой частью безопасности цепочки поставок программных продуктов. Оно позволяет вам наблюдать состояние всех рантайм-зависимостей, предоставляя данные по версиям компонентов, лицензиям и CVE (от англ. Common Vulnerabilities and Exposures — известные уязвимости и риски).  

При помощи плагинов систем сборки Maven и Gradle можно легко сгенерировать SBOM для проекта, и вашим заказчики станет доступна статистика безопасности его зависимостей. Однако, вам также необходимо быть уверенным в решениях, которые вы используете для разработки, включая рантаймы Java. Выбор поставщика Java-рантайма из тех, кто предоставляет SBOM, — хорошее решение для улучшения проектной безопасности.  

Также важно иметь SBOM для контейнерных образов, которые вы используете для разработки, потому что если вы не знаете внутрянки базовых образов, то не сможете адекватно среагировать на взлом или заражение через известные уязвимости (CVE). Это, в свою очередь, делает ваш продуктив чрезвычайно уязвимым к атакам. Вы можете сгенерировать SBOM, используя такие инструменты как Docker Scout, но получение SBOM от поставщика может оказаться более удобным вариантом.  

Регулярное обновление Java  

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

Значимые поставщики JDK предоставляют квартальные выпуски PSU (от англ. Patch Security Update — патч-обновление безопасности) и трое из них Oracle, BellSoft и Azul выпускают CPU-сборки как для LTS версий, так и для выпусков с новейшими версиями, включающими кроме них только критические исправления. CPU-сборки позволяют применять патчи безопасности без остановки продуктивного окружения.  

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

  

Oracle JDK  

Liberica JDK  

Amazon Corretto  

Azul Zulu  

IBM Semeru Runtimes  

Eclipse Temurin*  

Red Hat OpenJDK  

Окончание коммерческой поддержки старых версий Java  

JDK 6  

–  

Март 2026  

–  

Декабрь2027  

–  

–  

–  

JDK 7  

–  

Март 2026  

–  

Декабрь 2027  

–  

–  

–  

JDK 8  

Декабрь 2030  

Март 2031  

Май 2026  

Декабрь2030  

Ноябрь 2026  

–  

Ноябрь 2026  

JDK 11  

Сентябрь 2026  

Март 2032  

Сентябрь 2027  

Январь 2032  

Ноябрь 2026  

–  

Октябрь 2024  

Support period for newer Java versions  

JDK 17+  

8 лет  

8.5 лет  

7 лет  

8 лет  

6 лет  

–  

6 лет  

*Поддержка Eclipse Temurin осуществляется сторонними поставщиками.

Заключение

Версия Java-рантайма для Spring Boot может не иметь решающего значения если она верифицирована TCK. Однако, существуют важные показатели, такие как производительность, ассортимент контейнерных образов, дополнительные решения для повышения эффективности развертывания в облачных инфраструктурах и другие, которые делают некоторые рантаймы более предпочтительными для проектов на Spring Boot.  

Резюмируя все, что мы обсудили в этой статье, таблица ниже выделяет ключевые возможности для разработки на Spring Boot и их поддержку в рантаймах Java различных поставщиков.

Фича  

Oracle JDK  

Liberica JDK  

Amazon Corretto  

Azul Zulu  

IBM Semeru Runtimes  

Eclipse Temurin  

Red Hat OpenJDK  

TCK-верификация  

+  

+  

+  

+  

+  

+  

+  

Рекомендация Spring  

–  

+  

–  

–  

–  

–  

–  

Ассортимент инсталляторов и пакетных форматов(tar, deb, MSI, DMG, JDK/JREs)  

Нет apk  

Нет pkg  

Нет JRE  

+  

Нет dmg  

+  

+  

+  

Нет dmg  

Нет deb  

Нет apk  

Нет rpm  

Нет pkg  

Пакетные менеджеры, Docker-образы, установка из IntelliJ IDEA  

–  

+  

+  

+  

+  

+  

Нет установки из IDE  

Пакет с JavaFX  

–  

+  

Только для версии 8 и отдельных платформ  

+  

–  

–  

+  

Paketo buildpacks для Spring Boot  

Только с версии JDK17+  

+(по умолчаню)  

Только JDK  

+  

–  

+  

–  

Поддержка Alpine Linux   

+  

+  

+  

+  

–  

+  

–  

Наименьший размер образа с JRE  

–  

45.37 MB  

–  

72.43 MB  

96.44 MB  

62.5 MB  

126.7 MB  

Компилятор GraalVM Native Image   

Как часть Oracle GraalVM  

Liberica Native Image Kit (компилятор образов по умолчанию в Spring Boot)  

–  

–  

–  

–  

Mandrel для Quarkus  

Поддержка CRaC   

–  

+  

–  

+  

–  

–  

–  

Цикл бесплатных обновлений для LTS-версий  

3 года  

8.5 лет  

7 лет  

8 лет  

6 лет  

6 лет  

6 лет  

Стабилизированные CPU-сборки  

+  

+  

–  

+  

–  

–  

–  

SBOM  

+  

+  

+  

+  

+  

+  

+  

Решения для улучшения производительности проектов на Spring Boot 2.x   

+(для JDK 8)  

+(для JDK 8 и 11)  

–  

–  

–  

–  

–  

Наличие коммерческой поддержки  

+  

+  

Только для AWS  

+  

+  

Не от поставщика  

+  

Какие JRE вы используете для разработки и развертывания Spring Boot приложений? Напишите в комментариях. 


Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм - Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано.

Ждем всех, присоединяйтесь!

Комментарии (4)


  1. RustamKuramshin
    06.06.2024 11:15
    +4

    Несмотря на то, что эти улучшения могут быть востребованы не у всех команд разработки, встраивание JetBrains Runtime в инструменты в качестве среды по умолчанию делает ее одной из самых используемых среди Java-разработчиков.


    Обычно наверное рядовой разработчик устанавливает себе JDK "по вкусу", ставит IDEA и выбирает в ней SDK. Не видел, чтобы кто-то при разработке, локально на своей системе, использовал JetBrains Runtime для запуска проекта на Spring. Но классно, что IDEA в определенный момент позволила прям из интерфейса скачивать нужный JDK.

    Хотелось бы в последней таблице увидеть openjdk. Часто можно встретить Dockerfiles именно с таким jdk в базовом образе.

    Контейнеризированные приложения Spring Boot могут становиться достаточно тяжелы. Чтобы уменьшить их размер, вы можете использовать правильный базовый образ с JRE...


    Еще кроме тонких базовых образов есть возможность собрать свой рантайм засчет java modules и jlink. Было классно в статье об этом почитать тоже.


    1. amarkevich
      06.06.2024 11:15
      +2

      Часто можно встретить Dockerfiles именно с таким jdk в базовом образе.

      и очень зря - уже давно deprecated


      1. RustamKuramshin
        06.06.2024 11:15
        +1

        Про deprecated статус не знал кста. Но встречается-таки да. Ну и eclipse temurin естественно.


    1. csl
      06.06.2024 11:15

      Спрошу вас и @spring_aio : а Loom во всех рассмотренных рантаймах виден в JPMS, или ограничения последнего нужно обходить?