Как разогреть Java-классы, чтобы избежать медленного первого звонка?

13

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

В настоящее время первый вызов / вход в систему занимает 3,6 с, а следующие - 170 мс и то же самое для всех остальных маршрутов.

Я обнаружил, -XX:+TraceClassLoadingчто при первом вызове классы были загружены в память, что вызвало проблему с производительностью.

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

У кого-нибудь есть решение для автоматической загрузки классов приложения SpringBoot или прогрева всех его маршрутов?

Ybri
источник
Можете ли вы добавить больше деталей? Является ли ваше приложение экземплярами контроллеров? Или вы звоните в другие службы? Как вы звоните в другие службы?
Мениос
Spring Boot интенсивно использует классовое сканирование, поэтому вам не нужно «разогревать» что-либо, похожее на настольное приложение. Эта длительная начальная загрузка может быть результатом поиска ресурса - например, загрузки шаблона страницы.
Алексей Чернышев
Немного косвенный подход: если у вас есть 100% покрытие модульных тестов для конечных точек, вы можете использовать их. Вам все равно придется кодировать для каждой конечной точки, но вы получите что-то
отмечен
1
Может не быть идеальным в зависимости от проекта, который вы делаете, но вы можете вызывать свои конечные точки внутри, когда ваше приложение загружено.
omoshiroiii
@omoshiroiii в этом нет ничего плохого. мы делаем это. в производстве. причина связана с некоторыми динамическими библиотеками, которые используют, invokedynamicи мы знаем, что разрешение при первом вызове для них медленное (у нас есть десятки тысяч таких вызовов, которые без этого первого вызова накапливаются до десятков секунд).
Евгений

Ответы:

1

Загрузка классов Java ленива. Это означает, что класс загружается JVM только тогда, когда это необходимо и если это необходимо.

Если вы хотите принудительно загружать классы, вам просто нужно сослаться на них. Один из способов сделать это - перебирать содержимое jar или файлы классов, чтобы получить имена классов, а затем использовать их для вызова Class.forName(className).

Кроме того, если время запуска и производительность очень важны для вашего варианта использования, вы можете заранее рассмотреть решения для компиляции, такие как GraalVM , или уменьшить порог JIT для компиляции ( -XX:CompileThreshold).

andresp
источник
ни один из них не решит проблему ОП. загрузка все еще ленива в GraalVM и JITбессмысленна при первых вызовах .
Евгений
Кроме того, GraalVMэто хорошо, но, пожалуйста, взгляните на число проблем, которые он имеет в github: как только вы перейдете от проекта песочницы к чему-то большему (я смотрю на ваше отражение, в основном), вам будет немного больно, по крайней мере. моя точка зрения: переключиться на GraalVM - это не просто щелчок пальцами.
Евгений
Я думал о загрузке классов в банке, но я не нашел способ сделать это, у вас есть пример?
Ибри
@ Евгений, если вы прочитаете мой ответ, вы увидите, что я не сказал, что GraalVM или порог JIT изменит ленивость загрузки классов. Ответ на вопрос OP относительно ленивости - параграф перед этим. Последний абзац - всего лишь дополнительная подсказка на случай, если OP потребуется дополнительная оптимизация времени запуска / производительности помимо загрузки классов.
andresp
1
@Ybri, здесь есть другие вопросы с ответами, например stackoverflow.com/questions/2370867/…
andresp
0

Для меня единственный жизнеспособный вариант, который у вас есть class data sharing, это распространение по JEP 310 , JEP 341 и JEP 350 , но для этого, скорее всего, требуется java-13. Мы проводим внутреннее тестирование на моем рабочем месте (в основном для развлечения, а не для того, чтобы лгать), и результаты пока выглядят неплохо.

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

Евгений
источник
Как вы обрабатываете аутентификацию и конечные точки после публикации, чтобы избежать создания данных в вашей производственной базе данных?
Ибри
@Ybri, именно поэтому я и сказал, для некоторых это невозможно .
Евгений