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

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

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

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

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

Для большинства разработчиков не имеет большого значения, какой дистрибутив Java использовать, даже если они не используют Spring Boot или какой-либо другой фреймворк. Почему? Секрет в Technology Compatibility Kit или TCK (англ. — Комплект технологической совместимости).

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

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

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

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

Прошли те времена, когда скачивать JDK c веб-сайта его разработчика было нормой. Сейчас установка предпочитаемой IDE (Integrated Development Environment — англ. Интегрированная среда разработки) обеспечивает наличие требуемого runtime (англ. — программной среды выполнения) Java. Если это IntelliJ IDEA, то в качестве JDK по умолчанию будет JetBrains Runtime, fork (англ. — альтернативно развиваемая копия) 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 доступны к установке прямо из среды разработки IDE и достаточно популярны среди разработчиков. 

Специфика Spring Boot 

Spring Boot предлагает удобное решение для оформления вашего приложения в контейнерный образ без необходимости составлять Dockerfile — buildpacks. Однако, для такой задачи могут быть использованы не все Java-рантаймы. Paketo buildpacks (https://paketo.io/), используемый в Spring Boot, предлагает несколько дистрибутивов JDK в качестве основы для контейнерного образа. Выбор по умолчанию тут Liberica JDK, которая заодно является рантаймом, официально рекомендованным проектом 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 (от англ. Garbadge collector — сборщик мусора) такие как ZGC и ShenandoahGC (позднее исключенный из Oracle Java), которые разработаны для обеспечения максимальной отзывчивости в условиях работы с большим количеством используемой оперативной памяти. 

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

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

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

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

Таблица ниже отображает характеристики контейнерных образов для JDK 21, доступных на Docker Hub. Мы сравнили размеры сжатых образов JDK и JRE от различных поставщиков JDK с OS (от англ. Operating System — операционная система) слоями на 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 (от англ. Long Term Support — версия длительной поддержки) версий, так и для выпусков с новейшими версиями, включающими кроме них только критические исправления. 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 приложений? Напишите в комментариях. 

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