Spring Boot 3.3 раскрывает потенциал CDS (Class Data Sharing) благодаря двум новым функциям: самораспаковывающийся исполняемый JAR и поддержка Buildpacks CDS.
Команда Spring АйО перевела статью, в которой рассмотрены новые функции, нюансы их использования, а также их влияние на время запуска приложения.
Скрытый текст
Прежде чем читать статью, важно освоить несколько ключевых понятий. Без базовых знаний следующих инструментов будет сложно понять материал. Рекомендуем ознакомиться с ними заранее:
Чтобы повысить эффективность приложений Spring Boot в рантайме, минимизируя ограничения и сохраняя все преимущества фреймворка, разработчикам следует обратить внимание на поддержку CDS, появившуюся в версии Spring Boot 3.3. CDS (Class Data Sharing) ускоряет запуск приложений и снижает потребление памяти. Эта технология базируется на нововведениях Spring Framework 6.1, представленном несколько месяцев назад.
Ключевой момент заключается в том, что поддержка CDS представляет иные преимущества по сравнению с поддержкой GraalVM native image: улучшения, которые вы получаете с CDS, не такие радикальные, как с native images в плане времени запуска, но всё же очень значительные. При этом вы можете продолжать использовать свою обычную JVM с минимальными количеством побочных эффектов.
Spring Boot поддерживает как CDS, так и GraalVM native images в достаточной степени для использования в продакшене. Благодаря чему у вас появляется возможность выбрать подходящую именно вам технологию в зависимости от вашего контекста и предпочтений.
CDS – недооцененный шедевр JVM
CDS (Class Data Sharing) — это технология, которая уже давно используется в большинстве JVM, но не на полную мощность. Скорее всего, вы уже пользуетесь CDS, даже не подозревая об этом. Однако оптимизация через CDS обычно касается только загрузки классов самого JDK, тогда как классы вашего приложения или библиотек, скорее всего, остаются "за бортом". Чтобы это исправить, необходимо выполнить специальный "обучающий" запуск приложения.
При этом нужно соблюдать ряд условий, которые довольно легко нарушить без поддержки со стороны, например, такой как в Spring Boot:
Необходимо использовать туже самую JVM.
Classpath должен быть задан списком JAR-файлов, без использования каталогов, символов
*
и вложенных JAR.Важно сохранять временные метки JAR-файлов.
При использовании архива CDS в рабочем режиме, classpath должен быть точно таким же, каким был при создании архива. Дополнительные JAR или каталоги могут быть указаны в конце, но они не будут кэшироваться.
Spring Boot 3.3 раскрывает потенциал CDS благодаря двум новым функциям: самораспаковывающийся исполняемый JAR и поддержка Buildpacks CDS.
Самораспаковывающийся исполняемый JAR
Запуск приложения в продакшене с помощью команды java -jar my-app.jar
не является самым эффективным способом. Этот факт задокументирован, но многие разработчики, не использующие Buildpacks, упускают этот момент — это подтверждают многочисленные обсуждения в Spring-сообществе. До недавнего времени не существовало полноценной встроенной функции, которая могла бы помочь в этой ситуации.
Начиная со Spring Boot 3.3 ситуация поменялась, благодаря улучшениям связанным с самораспаковывающимися исполняемыми JAR-файлами. Теперь, чтобы извлечь JAR и запустить приложение, не требуется никаких внешних инструментов — достаточно команды java, которая, скорее всего, уже доступна в вашей среде.
java -Djarmode=tools -jar my-app.jar extract --destination application
После этого вы можете запускать Spring Boot приложение более эффективно, используя следующую команду:
java -jar application/my-app.jar
Стоит отметить, что эта функция обладает настоящей "суперсилой": она спроектирована с учётом требований CDS (и Project Leyden). В сочетании с поддержкой CDS в Spring Framework для training runs, вы можете создать CDS-архив для вашего Spring Boot приложения следующим образом:
java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar application/my-app.jar
Затем вы можете запускать приложение с включенным CDS при помощи команды:
java -XX:SharedArchiveFile=application.jsa -jar application/my-app.jar
Поддержка CDS и Spring AOT в Buildpacks
Функция самораспаковывающихся JAR файлов с использованием CDS удобна, но требует множества ручных действий. Чтобы упростить процесс, Spring Boot и Buildpacks предлагают встроенную поддержку CDS, которая:
Автоматически выполняет training run при создании образа контейнера.
Распаковывает Spring Boot JAR файл в структуру, оптимизированную для CDS.
Включает CDS архив в контейнер.
Автоматически активирует CDS при запуске образа контейнера.
Как показано в репозитории https://github.com/sdeleuze/spring-boot-cds-demo, CDS можно включить с использованием Gradle следующим образом:
tasks.named("bootBuildImage") {
environment["BP_JVM_CDS_ENABLED"] = "true"
}
А вот так с использованием Maven:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<env>
<BP_JVM_CDS_ENABLED>true</BP_JVM_CDS_ENABLED>
</env>
</image>
</configuration>
</plugin>
Во время training run Spring-объекты (beans) создаются без запуска жизненного цикла Spring, что на практике может привести к побочным эффектам. Например, к преждевременному взаимодействию с базой данных, которого можно избежать настроив приложение (или training run с использованием переменной окружения CDS_TRAINING_JAVA_TOOL_OPTIONS
), чтобы предотвратить такие взаимодействия, как описано на GitHub.
Также есть возможность включить поддержку Spring AOT с помощью переменной окружения BP_SPRING_AOT_ENABLED
. Однако важно учитывать следующие ограничения этого подхода:
Включите Spring AOT в сборку Maven или Gradle
Настройте Spring AOT для использования профиля Spring, который будет использоваться в продакшене
Переменные окружения
CDS_TRAINING_JAVA_TOOL_OPTIONS
иBP_SPRING_AOT_ENABLED
нельзя использовать одновременно
Команды Spring и Buildpacks активно работают над интеграцией этих возможностей с платформой Tanzu, чтобы обеспечить полноценную поддержку CDS для Cloud Foundry или Kubernetes. Под интеграцией я имею ввиду, например, автоконфигурацию training run и упрощенное включение CDS (вплоть до предоставления специального флага), без побочных эффектов. В будущем также планируются дополнительные возможности на уровне платформы.
Поговорим на языке фактов
При запуске минимального Spring MVC приложения на Tomcat на MacBook M2 мы наблюдаем, что приложение с использованием CDS загружается примерно в 1.5 раза быстрее и потребляет на 16% меньше памяти по сравнению с запуском исполняемого JAR. Если добавить в этот процесс Spring AOT, то загрузка ускоряется примерно в 2 раза, а потребление памяти уменьшается на 27%.
Похожие улучшения мы наблюдаем и для Petclinic.
Значения, очевидно, изменятся на менее мощных облачных серверах, но, вероятно, можно ожидать схожие улучшения в пропорциональном соотношении.
Spring Boot и Project Leyden
Интересно, что удобная для CDS структура, используемая новой командой extract, описанной выше, также разработана для обеспечения оптимальной производительности на ранних сборках Project Leyden. Этот проект можно считать преемником CDS с дополнительными возможностями, предоставляющими:
Еще более быстрый запуск приложения.
Более компактные образы контейнеров (за счёт удаления CDS архива из JDK и сохранения только архив приложения).
Ahead-Of-Time "прогрев" приложения для улучшения производительности после запуска и более быстрого достижения пиковой производительности.
На данный момент мы наблюдаем примерно в 3 раза более быстрый запуск Spring Boot приложений с Project Leyden и в 4 раза более быстрый при комбинировании Project Leyden и Spring AOT.
На предстоящей конференции Devoxx Belgium 2024 я выступлю с докладом о Project Leyden. Особенная радость — провести его вместе с участником команды Java Platform – Пером Минборгом.
Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм - Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано.
Ждем всех, присоединяйтесь