Прискорити час запуску весняного завантаження


115

У мене є програма Spring Boot. Я додав багато залежностей (на жаль, виглядає, що мені всі вони потрібні) і час запуску збільшився досить багато. Просто робити заняття SpringApplication.run(source, args)потрібно 10 секунд.

Хоча це може бути не дуже порівняно з тим, до чого "звикли", я незадоволений тим, що це забирає стільки, в основному тому, що це порушує потік розвитку. Сам додаток на даний момент досить малий, тому я припускаю, що більша частина часу пов'язана з додатковими залежностями, а не самими класами програм.

Я припускаю, що проблема полягає в скануванні на уроці, але я не знаю, як:

  • Підтвердьте, що це проблема (тобто як "налагодити" Spring Boot)
  • Якщо це справді причина, то як я можу її обмежити, щоб вона стала швидшою? Наприклад, якщо я знаю, що якась залежність або пакет нічого не містить, що Spring повинен сканувати, чи є спосіб обмежити це?

Я припускаю, що посилення Spring для паралельної ініціалізації бобів під час запуску пришвидшить ситуацію, але цей запит на покращення відкритий з 2011 року, без жодного прогресу. Я бачу деякі інші зусилля у самій Spring Boot, наприклад, дослідити покращення швидкості Tomcat JarScanning , але це специфічно для Tomcat і було відмовлено.

Ця стаття:

Хоча націлений на інтеграційні тести, пропонує використовувати lazy-init=true, однак я не знаю, як застосувати це до всіх бобів у Spring Boot за допомогою конфігурації Java - будь-які вказівники тут?

Будь-які (інші) пропозиції будуть вітатися.


Опублікуйте свій код. Зазвичай сканується лише той пакет, який визначено бігуном програми. Якщо у вас визначені інші пакети, @ComponentScanвони також будуть відскановані. Інша справа - переконатися, що ви не ввімкнули налагодження чи журнал слідів, оскільки загалом журнал повільний, дуже повільний.
М. Дейнум

Якщо ви використовуєте сплячку, вона також, як правило, їсть значний час при запуску програми.
Кнут Форкалсруд

Автоматичне прив'язування весни за типом у поєднанні з фабричними бобами може бути повільним, якщо ви додасте багато бобів та залежностей.
Кнут Форкалсруд

Або ви можете використовувати кешування, spring.io/guides/gs/caching
Касіян

2
Дякую всім за коментарі - я б не зміг розмістити код на жаль (багато внутрішніх банок), проте я все ще шукаю спосіб налагодити це. Так, я можу використовувати A або B або робити X або Y, що уповільнює його. Як це визначити? Якщо додати залежність X, яка має 15 перехідних залежностей, то як я можу знати, хто з цих 16 уповільнив її? Якщо я можу дізнатися, чи можу я зробити щось пізніше, щоб перешкодити весни їх вивчити? Такі покажчики були б корисні!
постійний дощ

Відповіді:


61

Spring Boot робить багато автоматичної конфігурації, яка може не знадобитися. Тому ви можете звузити лише автоматичну конфігурацію, необхідну для вашої програми. Щоб побачити повний список включеної автоматичної конфігурації, просто запустіть реєстрацію org.springframework.boot.autoconfigureв режимі DEBUG ( logging.level.org.springframework.boot.autoconfigure=DEBUGin application.properties). Інший варіант - запустити весняний завантажувальний додаток з --debugопцією:java -jar myproject-0.0.1-SNAPSHOT.jar --debug

Буде щось подібне у виході:

=========================
AUTO-CONFIGURATION REPORT
=========================

Перегляньте цей список і включіть лише потрібні автоконфігурації:

@Configuration
@Import({
        DispatcherServletAutoConfiguration.class,
        EmbeddedServletContainerAutoConfiguration.class,
        ErrorMvcAutoConfiguration.class,
        HttpEncodingAutoConfiguration.class,
        HttpMessageConvertersAutoConfiguration.class,
        JacksonAutoConfiguration.class,
        ServerPropertiesAutoConfiguration.class,
        PropertyPlaceholderAutoConfiguration.class,
        ThymeleafAutoConfiguration.class,
        WebMvcAutoConfiguration.class,
        WebSocketAutoConfiguration.class,
})
public class SampleWebUiApplication {

Код скопійовано з цієї публікації в блозі .


1
ти це міряв ??? Це було набагато швидше ?? На мою думку, це винятковий випадок, набагато важливіший, щоб переконатися, що кеш-
пам’ятка

@idmitriev Я щойно оцінив це у своїй програмі, і моя програма запущена за 53 секунди, порівняно з без виключення класів автоконфігурації було 73 секунди. Я виключав набагато більше класів, ніж перераховано вище.
apkisbossin

Приємно імпортувати всю конфігурацію. Як боротися з BatchConfigurerConfiguration.JpaBatchConfiguration Чи слід додати залежність до проекту? Як поводитися з рецензованими методами, такими як ConfigurationPropertiesRebinderAutoConfiguration # configurationPropertiesBeans?
користувач1767316

Як поводитися з приватними класами конфігурації?
користувач1767316

44

Найпопулярніша відповідь поки що не є помилковою, але вона не заглиблюється в глибину, яку я люблю бачити, і не дає жодних наукових доказів. Команда Spring Boot пройшла вправу для скорочення часу запуску Boot 2.0, а квиток 11226 містить багато корисної інформації. Існує також квиток 7939, відкритий для додавання інформації про терміни до оцінки стану, але, схоже, він не має конкретного еталону.

Найбільш корисним та методичним підходом для налагодження запуску Boot був здійснений Дейв Сайер. https://github.com/dsyer/spring-boot-startup-bench

У мене був подібний випадок використання, тому я взяв підхід Дейва до мікро-бенчмаркінгу з JMH і побіг з ним. Результат - проект завантаження . Я сконструював його таким чином, що його можна використовувати для вимірювання часу запуску для будь-якого додатка Spring Boot, використовуючи виконуваний jar, створений bootJar(раніше називався bootRepackageу Boot 1.5) завданням Gradle. Не соромтеся ним користуватися та надавати відгуки.

Мої висновки такі:

  1. Процесор має значення. Багато.
  2. Починаючи JVM з -Xverify: жоден не допомагає суттєво.
  3. Виключення непотрібних автоконфігурацій допомагає.
  4. Дейв рекомендував аргумент JVM -XX: TieredStopAtLevel = 1 , але мої тести не показали значного покращення з цим. Також, -XX:TieredStopAtLevel=1ймовірно, сповільнить ваш перший запит.
  5. Там було повідомлення про резолюцію імені хоста бути повільної, але я не знайшов , що це буде проблемою для додатків , які я тестував.

1
@ user991710 Не впевнений, як він зламався, але це виправлено зараз. Дякуємо за звіт.
Абхіджіт Саркар

2
Щоб додати до цього, чи можете ви додати приклад, як хтось може використовувати ваш орієнтир за допомогою спеціального додатка? Чи потрібно його додавати як проект, подібний до того minimal, чи може просто поставити банку? Я намагався це зробити, але не дуже далеко.
користувач991710

1
Не запускайте -Xverify:noneна виробництві, оскільки це порушує перевірку коду, і ви можете зіткнутися з проблемою. -XX:TieredStopAtLevel=1Гаразд, якщо ви запускаєте програму невелику тривалість (кілька секунд), інакше вона буде менш продуктивною, оскільки забезпечить JVM тривалими оптимізаціями роботи.
loicmathieu

3
oracle doc перераховує, Use of -Xverify:none is unsupported.що це означає?
сакура

1
Багато пулів (Oracle UCP точно), але в моєму тестуванні також Hikari і Tomcat) шифрують дані в пулі. Я насправді не знаю, шифрують вони інформацію про з'єднання чи обертають потік. Незважаючи на це, шифрування використовує генерацію випадкових чисел, і тому, маючи високодоступне джерело ентропії з високою пропускною здатністю, помітна різниця в продуктивності.
Даніель

18

Spring Boot 2.2.M1 має додаткову функцію для підтримки лінивої ініціалізації у Spring Boot.

За замовчуванням, коли контекст програми оновлюється, кожен боб у контексті створюється та вводяться його залежності. Навпаки, коли визначення біна налаштовано на ліниву ініціалізацію, воно не створюватиметься і його залежності не будуть вводитись, поки це не потрібно.

Увімкнення значення "Ізольована ініціалізація" встановлено spring.main.lazy-initializationна " true"

Коли ввімкнути ліниву ініціалізацію, лінива ініціалізація може запропонувати значні покращення часу запуску, але є і деякі помітні недоліки, і важливо включити її обережно

Для отримання більш детальної інформації, будь ласка, перевірте Док


3
якщо ввімкнути ледачу ініціалізацію, перший раз завантаження буде дуже швидким, але при першому зверненні до клієнта він може помітити деяку затримку. Я дуже рекомендую це для розробки, а не для виробництва.
Isuru Dewasurendra

Як запропонував @IsuruDewasurendra, це правильно не є рекомендованим способом, він може значно збільшити затримку, коли програма починає завантажувати завантаження.
Нарендра Яггі

Це просто штовхає банку по дорозі.
Абхіджіт Саркар

10

Як описано в цьому запитанні / відповіді, я думаю, що найкращим підходом є замість того, щоб додавати лише ті, які, на вашу думку, потрібні, виключати залежності, які ви знаєте, що вам не потрібно.

Дивіться: Мінімізуйте час запуску весняного завантаження

Підсумовуючи:

Ви можете бачити, що відбувається під кришками, і ввімкнути журнал налагодження так само просто, як і вказати --debug при запуску програми з командного рядка. Ви також можете вказати налагодження = true у своїй програмі.properties.

Крім того, ви можете встановити рівень реєстрації в application.properties так само просто, як:

logging.level.org.springframework.web: DEBUG logging.level.org.hibernate: ПОМИЛКА

Якщо ви виявите не налаштований автоматично налаштований модуль, його можна відключити. Документи для цього можна знайти тут: http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-disabling-specific-auto-configuration

Приклад виглядає так:

@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}

4

Добре є весь список можливих дій, описаних тут: https://spring.io/blog/2018/12/12/how-fast-is-spring

Я поставлю найважливіші нотатки з весняного боку (трохи коригується):

  • Винятки з Classpath з веб-пускачів Spring Boot:
    • Перевірка в сплячку
    • Джексон (але від цього залежать виконавчі механізми Spring Boot). Використовуйте Gson, якщо вам потрібна візуалізація JSON (працює лише з MVC поза коробкою).
    • Зворотний зв'язок: замість цього використовуйте slf4j-jdk14
  • Використовуйте індекс-показник весна-контекст. Це не додасть багато, але кожен маленький допомагає.
  • Не використовуйте пускачі, якщо ви не можете собі цього дозволити.
  • Використовуйте Spring Boot 2.1 та Spring 5.1. Перейдіть на 2.2 та 5.2, коли вони доступні.
  • Виправте розташування конфігураційних файлів Spring Boot за допомогою spring.config.location(аргумент командного рядка або властивість системи тощо). Приклад тестування в IDE:spring.config.location=file://./src/main/resources/application.properties .
  • Вимкніть JMX, якщо він вам не потрібен spring.jmx.enabled=false(це значення за замовчуванням у Spring Boot 2.2)
  • Зробіть визначення квасолі ледачими за замовчуванням. У spring.main.lazy-initialization=trueSpring Boot 2.2 з'явився новий прапор (використовується LazyInitBeanFactoryPostProcessorдля старих Spring).
  • Розпакуйте жирову банку і запустіть явним шляхом.
  • Запустіть JVM за допомогою -noverify. Також врахуйте -XX:TieredStopAtLevel=1(що згодом уповільнить JIT за рахунок заощадженого часу запуску).

Згадане LazyInitBeanFactoryPostProcessor(ви можете використовувати його для Spring 1.5, якщо ви не можете застосувати прапор, spring.main.lazy-initialization=trueдоступний з Spring 2.2):

public class LazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
      for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
        definition.setLazyInit(true);
      }
  }
}

Ви також можете використовувати (або написати своє - це просто) щось, щоб проаналізувати час ініціалізації бобів: https://github.com/lwaddicor/spring-startup-analysis

Сподіваюся, це допомагає!


0

У моєму випадку було дуже багато точок прориву. Коли я натиснув "Mute Breakpoints" і перезапустив програму в режимі налагодження, додаток запустилося в 10 разів швидше.


-1

Якщо ви намагаєтеся оптимізувати розгортання розробки для ручного тестування, я настійно рекомендую використовувати devtools .

Програми, які використовують spring-boot-devtools, автоматично перезапускаються кожного разу, коли файли на classpath змінюються.

Просто перекомпілюйте - і сервер перезавантажиться (для Groovy вам потрібно лише оновити вихідний файл). якщо ви використовуєте IDE (наприклад, 'vscode'), він може автоматично компілювати ваші файли java, тому просто збереження файлу java може ініціювати перезапуск сервера, опосередковано - і Java стає настільки ж безпроблемною, як і Groovy в цьому плані.

Краса такого підходу полягає в тому, що поступовий перезапуск короткого замикання виконує деякі етапи запуску з нуля - тому ваша послуга буде резервна копія та запуск набагато швидше!


На жаль, це не допомагає з часом запуску для розгортання або автоматизованого тестування блоку.


-1

ПОПЕРЕДЖЕННЯ. Якщо ви не використовуєте Hibernate DDL для автоматичного створення схеми БД і не використовуєте кеш L2, ця відповідь НЕ стосується вас. Прокрутіть вперед.

Я вважаю, що Hibernate додає значного часу на запуск програми. Відключення кешу L2 та ініціалізації бази даних прискорює запуск програми Spring Boot. Залиште кеш увімкнено для виробництва та відключіть його для свого середовища розробки.

application.yml:

spring:
  jpa:
    generate-ddl: false
    hibernate:
      ddl-auto: none
    properties:
      hibernate:
        cache:
          use_second_level_cache: false
          use_query_cache: false

Результати тесту:

  1. Кеш L2 увімкнено та ddl-auto: update

    INFO 5024 --- [restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 23331 ms
    INFO 5024 --- [restartedMain] b.n.spring.Application : Started Application in 54.251 seconds (JVM running for 63.766)
  2. Кеш L2 вимкнено і ddl-auto: none

    INFO 10288 --- [restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 9863 ms
    INFO 10288 --- [restartedMain] b.n.spring.Application : Started Application in 32.058 seconds (JVM running for 37.625)

Тепер мені цікаво, що я буду робити з усім цим вільним часом


hibernate.hbm2ddl.auto = оновлення не має нічого спільного з кешем l2. ddl .. = update вказує на сканування поточної схеми бази даних та обчислення необхідного sql, щоб оновити схему для відображення ваших сутностей. "None" не робить цю перевірку (також не намагається оновити схему). Найкраща практика полягає у використанні такого інструменту, як liquidibase, де ви обробляєте зміни вашої схеми, а також можете відстежувати їх.
Radu Toader

@RaduToader це питання, і моя відповідь стосується прискорення часу запуску Spring Boot. Вони не мають нічого спільного з обговоренням в режимі Hibernate DDL vs Liquibase; ці засоби мають і свої плюси, і мінуси. Моя думка полягає в тому, що ми можемо вимкнути оновлення схеми БД і ввімкнути її лише за потреби. Hibernate потребує значного часу на запуск, навіть коли модель не змінювалася з моменту останнього запуску (для порівняння схеми БД з автогенерованою схемою). Те саме стосується кешу L2.
naXa

так, я це знаю, але моя думка полягала в тому, що це трохи небезпечно, щоб не пояснити, що це справді робить. Ви можете дуже легко закінчитись з порожнім db.
Раду

@RaduToader У моїй відповіді було посилання на сторінку документації про ініціалізацію БД. Ви це читали? Він містить вичерпний посібник, в якому перераховані всі найпопулярніші інструменти (сплячий режим і Liquibase, а також JPA та Flyway). Також сьогодні я додаю чітке попередження до верхньої частини своєї відповіді. Як ви вважаєте, мені потрібні інші зміни для пояснення наслідків?
naXa

Ідеально. Дякую
Radu Toader

-3

Мені дивно, що раніше ніхто не пропонував цих оптимізацій. Ось декілька загальних порад щодо оптимізації створення та запуску проекту при розробці:

  • виключити каталоги розробок із антивірусного сканера:
    • каталог проектів
    • побудувати вихідний каталог (якщо він знаходиться поза каталогом проектів)
    • Каталог індексів IDE (наприклад, ~ / .IntelliJIdea2018.3)
    • каталог розгортання (веб-сайти в Tomcat)
  • оновити обладнання. використовувати швидші процесор і оперативну пам’ять, кращі підключення до Інтернету (для завантаження залежностей) та підключення до бази даних, перехід на SSD. відеокарта не має значення.

ПОПЕРЕДЖЕННЯ

  1. перший варіант стосується ціни зниженої безпеки.
  2. другий варіант коштує грошей (очевидно).

Питання стосується покращення часу завантаження, а не часу компіляції.
ArtOfWarfare

@ArtOfWarfare прочитайте питання ще раз. питання задає проблему як "я незадоволений тим, що це займає стільки [часу], здебільшого тому, що це порушує потік розвитку". Я відчував, що це головна проблема і вирішив її у своїй відповіді.
naXa

-9

Для мене це здається, що ви використовуєте неправильний параметр конфігурації. Почніть з перевірки myContainer та можливих конфліктів. Щоб визначити, хто використовує найбільше ресурсів, вам потрібно перевірити карти пам'яті (див. Кількість даних!) Для кожної залежності одночасно - і це також потребує багато часу (а також привілеї SUDO). До речі: ти зазвичай тестуєш код на залежність?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.