Spring Boot 시작 시간 단축


115

Spring Boot 애플리케이션이 있습니다. 나는 많은 의존성을 추가했고 (불행히도 그것들이 모두 필요해 보인다) 시작 시간이 상당히 증가했다. 하는 것만으로도 SpringApplication.run(source, args)10 초가 걸립니다.

그것이 "사용 된"것에 비하면 그다지 많지 않을 수도 있지만, 대부분 개발 흐름을 깨뜨리기 때문에 그렇게 많이 걸리는 것이 불행합니다. 이 시점에서 애플리케이션 자체는 다소 작기 때문에 대부분의 시간이 앱 클래스 자체가 아니라 추가 된 종속성과 관련이 있다고 가정합니다.

문제가 클래스 경로 스캔이라고 가정하지만 다음 방법을 잘 모르겠습니다.

  • 문제인지 확인 (예 : Spring Boot를 "디버그"하는 방법)
  • 그것이 정말로 원인이라면 어떻게 제한 할 수 있습니까? 예를 들어 일부 종속성 또는 패키지에 Spring이 스캔해야하는 내용이 포함되어 있지 않다는 것을 알고 있다면이를 제한하는 방법이 있습니까?

나는 시작하는 동안 병렬 빈 초기화를 갖도록 Spring을 강화 하면 속도가 빨라질 것이라고 가정 하지만 그 향상 요청은 2011 년부터 진행되지 않고 열려 있습니다. Investigate Tomcat JarScanning 속도 향상 과 같은 Spring Boot 자체의 다른 노력이 있지만 Tomcat에 국한되어 포기되었습니다.

이 기사 :

통합 테스트를 겨냥했지만을 사용 lazy-init=true하는 것이 좋지만 Java 구성을 사용하여 Spring Boot의 모든 Bean에 이것을 적용하는 방법을 모르겠습니다-여기에 포인터가 있습니까?

(기타) 제안을 환영합니다.


코드를 게시하십시오. 일반적으로 애플리케이션 실행기가 정의 된 패키지 만 스캔됩니다. 다른 패키지가 정의되어 있으면 @ComponentScan해당 패키지 도 스캔됩니다. 또 다른 한 가지는 일반적으로 로깅이 느리고 매우 느리기 때문에 디버그 또는 추적 로깅을 활성화하지 않았는지 확인하는 것입니다.
M. Deinum 2014

Hibernate를 사용하면 응용 프로그램 시작시 상당한 시간을 소모하는 경향이 있습니다.
Knut Forkalsrud 2015 년

Spring의 유형별 자동 바인딩은 팩토리 빈과 결합되어 많은 빈과 종속성을 추가하면 느려질 가능성이 있습니다.
Knut Forkalsrud 2015 년

아니면 캐싱을 사용할 수 있습니다 spring.io/guides/gs/caching
Cassian

2
의견을 보내 주셔서 감사합니다-불행히도 코드를 게시 할 수는 없지만 (많은 내부 항아리), 여전히 이것을 디버깅하는 방법을 찾고 있습니다. 예, A 또는 B를 사용하거나 X 또는 Y를 사용하여 속도가 느려질 수 있습니다. 이것을 어떻게 결정합니까? 15 개의 전이 종속성이있는 종속성 X를 추가하면 16 개 중 어느 것이 속도를 늦추는 지 어떻게 알 수 있습니까? 알아낼 수 있다면 나중에 Spring이 검사하는 것을 막기 위해 할 수있는 일이 있습니까? 그런 포인터가 유용 할 것입니다!
꾸준한 비

답변:


61

Spring Boot는 필요하지 않을 수있는 많은 자동 구성을 수행합니다. 따라서 앱에 필요한 자동 구성 만 좁힐 수 있습니다. 포함 된 자동 구성의 전체 목록을 보려면 org.springframework.boot.autoconfigureDEBUG 모드 ( 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
이거 측정 했니 ?? 훨씬 빨랐나요 ?? 제 생각에는 이것은 예외적 인 경우입니다. Spring 테스트 컨텍스트 캐시가 작동하는지 확인하는 것이 훨씬 더 중요합니다
idmitriev

@idmitriev 방금 내 응용 프로그램에서 이것을 측정했으며 자동 구성 클래스를 제외하지 않은 것과 비교하여 53 초에 응용 프로그램이 시작되었습니다. 73 초였습니다. 그래도 위에 나열된 것보다 더 많은 클래스를 제외했습니다.
apkisbossin

모든 구성을 가져 오는 것이 좋습니다. BatchConfigurerConfiguration.JpaBatchConfiguration을 처리하는 방법은 projet에 종속성을 추가해야합니까? ConfigurationPropertiesRebinderAutoConfiguration # configurationPropertiesBeans와 같은 참조 된 메서드를 처리하는 방법은 무엇입니까?
user1767316

개인 구성 클래스를 처리하는 방법은 무엇입니까?
user1767316

44

지금까지 가장 많이 득표 한 답변은 틀린 것은 아니지만 내가보고 싶은 깊이에 이르지 않으며 과학적 증거를 제공하지 않습니다. Spring Boot 팀은 Boot 2.0의 시작 시간을 줄이기위한 연습을 진행했으며 티켓 11226 에는 많은 유용한 정보가 포함되어 있습니다. 조건 평가에 타이밍 정보를 추가 할 수 있는 티켓 7939 도 있지만 특정 ETA가없는 것 같습니다.

부팅 시작 디버깅을위한 가장 유용하고 체계적인 접근 방식은 Dave Syer에 의해 수행되었습니다. https://github.com/dsyer/spring-boot-startup-bench

저도 비슷한 사용 사례를 가지고 있었기 때문에 JMH로 마이크로 벤치마킹에 대한 Dave의 접근 방식을 취해 실행했습니다. 결과는 boot-benchmark 프로젝트입니다. 나는 의해 생성 된 실행 항아리 사용하여 임의의 봄 부팅 응용 프로그램의 시작 시간을 측정 할 수는 있도록 설계 bootJar(이전이라고 bootRepackage부팅 1.5) Gradle을 작업. 자유롭게 사용하고 피드백을 제공하십시오.

내 결과는 다음과 같습니다.

  1. CPU가 중요합니다. 많이.
  2. -Xverify : none으로 JVM을 시작 하면 큰 도움이됩니다.
  3. 불필요한 자동 구성을 제외하면 도움이됩니다.
  4. Dave는 JVM 인수 -XX : TieredStopAtLevel = 1을 권장 했지만 내 테스트는 그와 관련하여 크게 개선되지 않았습니다. 또한 -XX:TieredStopAtLevel=1첫 번째 요청이 느려질 것입니다.
  5. 가 있었다 보고서 호스트 이름 확인이 느린되는,하지만 난 그것이 내가 테스트 응용 프로그램에 대한 문제 찾지 못했습니다.

1
@ user991710 어떻게 고장 났는지 확실하지 않지만 지금은 해결되었습니다. 신고 해 주셔서 감사합니다.
Abhijit Sarkar

2
여기에 추가하려면 다른 사람이 사용자 지정 응용 프로그램으로 벤치 마크를 사용하는 방법에 대한 예를 추가해 주시겠습니까? 과 유사한 프로젝트로 추가해야합니까 minimal, 아니면 단지 제공 할 수 있습니까? 나는 전자를 시도했지만 그리 멀지 않았습니다.
user991710

1
-Xverify:none코드 검증을 위반하고 문제가 발생할 수 있으므로 프로덕션에서 실행하지 마십시오 . -XX:TieredStopAtLevel=1짧은 기간 (몇 초) 동안 애플리케이션을 실행하면 괜찮습니다. 그렇지 않으면 JVM에 장기 실행 최적화를 제공하므로 생산성이 떨어집니다.
loicmathieu

3
오라클 문서에는 Use of -Xverify:none is unsupported.그 의미가 무엇입니까?
sakura

1
많은 풀 (확실히 Oracle UCP이지만 내 테스트에서는 Hikari 및 Tomcat도 있음)이 풀의 데이터를 암호화합니다. 실제로 그들이 연결 정보를 암호화하는지 또는 스트림을 래핑하는지는 모릅니다. 어쨌든 암호화는 난수 생성을 사용하므로 가용성이 높고 처리량이 높은 엔트로피 소스를 사용하면 성능에 눈에 띄는 차이가 있습니다.
Daniel

18

Spring Boot 2.2.M1 은 Spring Boot에서 Lazy Initialization을 지원하는 기능을 추가했습니다.

기본적으로 애플리케이션 컨텍스트가 새로 고쳐질 때 컨텍스트의 모든 Bean이 작성되고 해당 종속성이 삽입됩니다. 대조적으로 빈 정의가 느리게 초기화되도록 구성되면 생성되지 않으며 필요할 때까지 종속성이 주입되지 않습니다.

지연 초기화 활성화spring.main.lazy-initializationtrue로 설정

지연 초기화를 활성화해야하는 경우 지연 초기화는 시작 시간을 크게 향상시킬 수 있지만 몇 가지 눈에 띄는 단점도 있으며주의해서 활성화하는 것이 중요합니다.

자세한 내용은 Doc을 확인하십시오.


3
지연 초기화를 활성화하면 처음로드하는 것이 매우 빠르지 만 클라이언트가 처음 액세스 할 때 약간의 지연이 발생할 수 있습니다. 프로덕션 용이 아닌 개발 용으로 정말 추천합니다.
Isuru Dewasurendra

@IsuruDewasurendra가 제안했듯이 권장되는 방법은 아니며 앱이로드를 제공하기 시작할 때 지연 시간을 크게 늘릴 수 있습니다.
Narendra Jaggi

그것은 단지 길 아래로 캔을 차 버립니다.
Abhijit Sarkar

10

이 질문 / 답변에서 설명했듯이 가장 좋은 방법은 필요하다고 생각하는 것만 추가하는 대신 필요하지 않다는 것을 알고있는 종속성을 제외하는 것입니다.

참조 : Spring Boot 시작 시간 최소화

요약해서 말하자면:

명령 줄에서 애플리케이션을 시작할 때 --debug를 지정하는 것처럼 간단하게 진행중인 작업을 확인하고 디버그 로깅을 활성화 할 수 있습니다. application.properties에서 debug = true를 지정할 수도 있습니다.

또한 application.properties의 로깅 수준을 다음과 같이 간단하게 설정할 수 있습니다.

logging.level.org.springframework.web : DEBUG logging.level.org.hibernate : ERROR

원하지 않는 자동 구성 모듈을 감지하면 비활성화 할 수 있습니다. 이에 대한 문서는 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

Spring 측에서 가장 중요한 메모를 넣을 것입니다 (조금 조정 됨).

  • Spring Boot 웹 스타터의 클래스 경로 제외 :
    • Hibernate Validator
    • Jackson (그러나 Spring Boot 액추에이터는 그것에 의존합니다). JSON 렌더링이 필요한 경우 Gson을 사용하십시오 (기본적으로 MVC에서만 작동).
    • Logback : 대신 slf4j-jdk14 사용
  • spring-context-indexer를 사용하십시오. 많은 것을 추가하지는 않지만 모든 작은 것이 도움이됩니다.
  • 여유가 없다면 액추에이터를 사용하지 마십시오.
  • Spring Boot 2.1 및 Spring 5.1을 사용하십시오. 가능한 경우 2.2 및 5.2로 전환하십시오.
  • spring.config.location(명령 줄 인수 또는 시스템 속성 등) 을 사용하여 Spring Boot 구성 파일의 위치를 ​​수정합니다 . 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에 사용).
  • fat jar의 압축을 풀고 명시적인 클래스 경로로 실행하십시오.
  • .NET을 사용하여 JVM을 실행합니다 -noverify. 또한 고려하십시오 -XX:TieredStopAtLevel=1(그러면 나중에 시작 시간이 절약되는 대신 JIT 속도가 느려짐).

언급 한 것 LazyInitBeanFactoryPostProcessor( spring.main.lazy-initialization=trueSpring 2.2에서 사용 가능한 플래그를 적용 할 수없는 경우 Spring 1.5 에서 사용할 수 있음) :

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를 사용하는 애플리케이션은 클래스 경로의 파일이 변경 될 때마다 자동으로 다시 시작됩니다.

다시 컴파일하면 서버가 자동으로 다시 시작됩니다 (Groovy의 경우 소스 파일 만 업데이트하면 됨). IDE (예 : 'vscode')를 사용하는 경우 Java 파일을 자동으로 컴파일 할 수 있으므로 Java 파일을 저장하는 것만으로도 간접적으로 서버를 다시 시작할 수 있으며 Java는 이와 관련하여 Groovy만큼 매끄럽게됩니다.

이 접근 방식의 장점은 증분 재시작이 처음부터 시작하는 일부 시작 단계를 단락시켜 서비스가 훨씬 더 빠르게 백업되고 실행된다는 것입니다.


불행히도 이것은 배포 또는 자동화 된 단위 테스트를위한 시작 시간에 도움이되지 않습니다.


-1

경고 : 자동 DB 스키마 생성에 Hibernate DDL을 사용하지 않고 L2 캐시를 사용하지 않는 경우이 답변은 적용되지 않습니다. 앞으로 스크롤하십시오.

내 발견은 Hibernate가 애플리케이션 시작에 상당한 시간을 추가한다는 것입니다. L2 캐시 및 데이터베이스 초기화 비활성화 하면 Spring Boot 앱 시작이 빨라집니다. 프로덕션을 위해 캐시를 ON 상태로두고 개발 환경을 위해 비활성화하십시오.

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 = update는 l2 캐시와 관련이 없습니다. ddl .. = update는 현재 데이터베이스 스키마를 스캔하고 엔티티를 반영하도록 스키마를 업데이트하기 위해 필요한 SQL을 계산하도록 지정합니다. 'None'은이 확인을 수행하지 않습니다 (또한 스키마 업데이트를 시도하지 않음). 모범 사례는 스키마 변경 사항을 처리하고 추적 할 수도있는 liquibase와 같은 도구를 사용하는 것입니다.
Radu Toader

@RaduToader이 질문과 내 대답은 Spring Boot 시작 시간을 단축하는 것에 관한 것입니다. 그들은 Hibernate DDL 대 Liquibase 토론과는 아무 관련이 없습니다. 이러한 도구에는 장단점이 있습니다. 내 요점은 DB 스키마 업데이트를 비활성화하고 필요한 경우에만 활성화 할 수 있다는 것입니다. Hibernate는 마지막 실행 이후 모델이 변경되지 않은 경우에도 시작시 상당한 시간이 걸립니다 (DB 스키마와 자동 생성 된 스키마 비교). L2 캐시도 마찬가지입니다.
naXa 2019

네, 알아요.하지만 제 요점은 이것이 진정으로하는 일을 설명하지 않는 것이 약간 위험하다는 것입니다. 당신은 당신의 db가 빈 상태로 쉽게 끝날 수 있습니다.
Radu Toader

@RaduToader 내 대답에는 DB 초기화에 대한 문서 페이지에 대한 링크가 있습니다. 읽었 어? 여기에는 가장 인기있는 모든 도구 (Hibernate 및 Liquibase, JPA 및 Flyway)를 나열하는 전체 가이드가 포함되어 있습니다. 또한 오늘 나는 내 대답 상단에 명확한 경고를 추가합니다. 결과를 설명하기 위해 다른 변경이 필요하다고 생각하십니까?
naXa

완전한. 주셔서 감사합니다
라두 Toader에게

-3

아무도 이전에 이러한 최적화를 제안하지 않았다는 것이 이상합니다. 다음은 개발시 프로젝트 빌드 및 시작 최적화에 대한 몇 가지 일반적인 팁입니다.

  • 바이러스 백신 스캐너에서 개발 디렉토리 제외 :
    • 프로젝트 디렉토리
    • 빌드 출력 디렉토리 (프로젝트 디렉토리 외부에있는 경우)
    • IDE 색인 디렉토리 (예 : ~ / .IntelliJIdea2018.3)
    • 배포 디렉터리 (Tomcat의 웹앱)
  • 하드웨어를 업그레이드하십시오. 더 빠른 CPU 및 RAM, 더 나은 인터넷 연결 (종속성 다운로드 용) 및 데이터베이스 연결을 사용하고 SSD로 전환합니다. 비디오 카드는 중요하지 않습니다.

경고

  1. 첫 번째 옵션은 보안 감소의 대가입니다.
  2. 두 번째 옵션은 (분명히) 돈이 든다.

문제는 컴파일 시간이 아니라 부팅 시간을 개선하는 것입니다.
ArtOfWarfare

@ArtOfWarfare는 질문을 다시 읽었습니다. 이 질문은 문제를 "그렇게 [시간]이 걸린다는 것이 불행합니다. 대부분 개발 흐름을 깨뜨리기 때문입니다."라고 말합니다. 나는 이것이 주요 문제라고 느꼈고 내 대답에서 해결했습니다.
naXa 2010 년

-9

나에게는 잘못된 구성 설정을 사용하는 것 같습니다. myContainer 및 가능한 충돌을 확인하여 시작하십시오. 누가 가장 많은 리소스를 사용하고 있는지 확인하려면 한 번에 각 종속성에 대한 메모리 맵 (데이터 양 참조!)을 확인해야합니다. 또한 많은 시간이 걸립니다 ... (및 SUDO 권한). 그건 그렇고 : 일반적으로 종속성에 대해 코드를 테스트합니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.