Spring Boot başlangıç ​​süresini hızlandırın


115

Spring Boot uygulamam var. Çok fazla bağımlılık ekledim (maalesef hepsine ihtiyacım var gibi görünüyor) ve başlangıç ​​süresi oldukça arttı. Sadece a yapmak SpringApplication.run(source, args)10 saniye sürer.

Bu, "alışkın" olanla kıyaslanamayacak kadar fazla olmasa da, çoğunlukla geliştirme akışını bozduğu için bu kadar zaman almasından mutsuzum. Bu noktada uygulamanın kendisi oldukça küçüktür, bu yüzden çoğu zaman uygulama sınıflarının kendileri ile değil, eklenen bağımlılıklar ile ilgili olduğunu varsayıyorum.

Sorunun sınıf yolu taraması olduğunu varsayıyorum, ancak şunları nasıl yapacağımı bilmiyorum:

  • Sorunun bu olduğunu onaylayın (yani, Spring Boot nasıl "hata ayıklanacağı")
  • Eğer gerçekten sebep buysa, daha hızlı olması için onu nasıl sınırlayabilirim? Örneğin, bazı bağımlılıkların veya paketlerin Spring'in taraması gereken hiçbir şey içermediğini biliyorsam, bunu sınırlamanın bir yolu var mı?

Spring'in başlatma sırasında paralel fasulye başlatmaya sahip olmasını sağlamanın işleri hızlandıracağını varsayıyorum , ancak bu geliştirme talebi 2011'den beri herhangi bir ilerleme olmadan açık. Spring Boot'un kendisinde, Investigate Tomcat JarScanning hız iyileştirmeleri gibi bazı başka çabalar görüyorum , ancak bu Tomcat'e özeldir ve terk edilmiştir.

Bu makale:

entegrasyon testlerini hedeflemesine rağmen, kullanmayı önerir lazy-init=true, ancak bunu Java yapılandırmasını kullanarak Spring Boot'taki tüm fasulyelere nasıl uygulayacağımı bilmiyorum - burada herhangi bir işaret var mı?

Herhangi bir (diğer) öneri memnuniyetle karşılanacaktır.


Kodunuzu gönderin. Normalde yalnızca uygulama çalıştırıcısının tanımladığı paket taranır. İçin tanımlanmış başka paketleriniz varsa@ComponentScan . Başka bir şey de, genellikle günlüğe kaydetme yavaş ve çok yavaş olduğundan, hata ayıklama veya izleme günlüğünü etkinleştirmediğinizden emin olmaktır.
M.Deinum

Hazırda Bekletme'yi kullanırsanız, uygulama başlangıcında da önemli ölçüde zaman yeme eğilimindedir.
Knut Forkalsrud

Baharın fabrika çekirdekleriyle birleştirilmiş türe göre otomatik bağlama, çok sayıda fasulye ve bağımlılık eklediğinizde yavaş olma potansiyeline sahiptir.
Knut Forkalsrud

Veya önbelleğe almayı kullanabilirsiniz, spring.io/guides/gs/caching
Cassian

2
Yorumlar için hepinize teşekkürler - Maalesef kodu gönderemem (birçok dahili kavanoz), ancak yine de bu hatayı gidermenin bir yolunu arıyorum. Evet, A veya B kullanıyor olabilirim veya X veya Y yapıyor olabilirim, bu da onu yavaşlatır. Bunu nasıl belirlerim? 15 geçişli bağımlılığı olan bir X bağımlılığı eklersem, bu 16 bağımlılıktan hangisinin onu yavaşlattığını nasıl bilebilirim? Bulabilirsem, Spring'in onları incelemesini engellemek için daha sonra yapabileceğim bir şey var mı? Bunun gibi işaretçiler faydalı olacaktır!
sabit yağmur

Yanıtlar:


61

Spring Boot, ihtiyaç duyulmayabilecek birçok otomatik yapılandırma gerçekleştirir. Bu nedenle, yalnızca uygulamanız için gerekli olan otomatik yapılandırmayı daraltmak isteyebilirsiniz. Dahil edilen otomatik yapılandırmanın tam listesini görmek için, günlüğe kaydetmeyi org.springframework.boot.autoconfigureDEBUG modunda ( logging.level.org.springframework.boot.autoconfigure=DEBUGin application.properties) çalıştırın. Diğer bir seçenek, bahar önyükleme uygulamasını şu seçenekle çalıştırmaktır --debug:java -jar myproject-0.0.1-SNAPSHOT.jar --debug

Çıktıda şöyle bir şey olacaktır:

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

Bu listeyi inceleyin ve yalnızca ihtiyacınız olan otomatik yapılandırmaları dahil edin:

@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 {

Kod bu blog gönderisinden kopyalandı .


1
bunu ölçtün mü ??? Çok daha hızlı mıydı? Bence bu istisnai bir durum, Spring test bağlam önbelleğinin çalıştığından emin olmak için çok daha önemli
idmitriev

@idmitriev Bunu uygulamamda yeni ölçtüm ve uygulamam 53 saniyede başladı, otomatik konfigürasyon sınıfları hariç tutulmadan 73 saniyeydi. Yine de yukarıda listelenenden çok daha fazla sınıfı dışladım.
apkisbossin

Tüm Yapılandırmayı İçe Aktarmak Güzel. Projeye bağımlılık eklenmelidir BatchConfigurerConfiguration.JpaBatchConfiguration ile nasıl başa çıkılır? ConfigurationPropertiesRebinderAutoConfiguration # configurationPropertiesBeans gibi başvurulan yöntemlerle nasıl başa çıkılır?
user1767316

Özel yapılandırma sınıflarıyla nasıl başa çıkılır?
user1767316

44

Şimdiye kadar en çok oylanan cevap yanlış değil ama görmek istediğim derinliğe inmiyor ve hiçbir bilimsel kanıt sunmuyor. Spring Boot ekibi, Boot 2.0 için başlatma süresini kısaltmak için bir alıştırma yaptı ve 11226 numaralı bilet birçok faydalı bilgi içeriyor. Bir de 7939 bileti varDurum değerlendirmesine zamanlama bilgisi eklemeye açık , ancak belirli bir sahip görünmüyor.

Boot başlangıcında hata ayıklamak için en kullanışlı ve metodik yaklaşım Dave Syer tarafından yapılmıştır. https://github.com/dsyer/spring-boot-startup-bench

Benim de benzer bir kullanım durumum vardı, bu yüzden Dave'in JMH ile mikro kıyaslama yaklaşımını aldım ve onunla koştum. Sonuç, önyükleme kıyaslama projesidir. Tarafından üretilen yürütülebilir jar kullanarak herhangi bir Spring Boot uygulaması için başlatma süresini ölçmek için kullanılabilecek şekilde tasarladım bootJar(öncedenbootRepackage Gradle görevi jar'i Boot 1.5'te deniyordu) kullanarak. Kullanmaktan ve geri bildirimde bulunmaktan çekinmeyin.

Bulgularım şu şekildedir:

  1. CPU önemlidir. Çok.
  2. JVM'yi -Xverify ile başlatmak: hiçbiri önemli ölçüde yardımcı olur.
  3. Gereksiz otomatik yapılandırmaları hariç tutmak yardımcı olur.
  4. Dave, JVM bağımsız değişkenini önerdi -XX: TieredStopAtLevel = 1 , ancak benim testlerim bu konuda önemli bir gelişme göstermedi. Ayrıca, -XX:TieredStopAtLevel=1muhtemelen ilk isteğinizi yavaşlatacaktır.
  5. Ana bilgisayar adı çözümlemesinin yavaş olduğuna dair raporlar var , ancak bunu test ettiğim uygulamalar için bir sorun olarak görmedim.

1
@ user991710 Nasıl kırıldığından emin değilim, ama şimdi düzeltildi. Rapor için teşekkürler.
Abhijit Sarkar

2
Buna ek olarak, başka birinin özel bir uygulamayla kıyaslamanızı nasıl kullanabileceğine dair bir örnek ekler misiniz? Benzer bir proje olarak eklenmesi gerekiyor mu minimal, yoksa kavanoz basitçe sağlanabilir mi? İlkini yapmaya çalıştım ama çok uzağa gitmedim.
user991710

1
Kaçma -Xverify:noneo kod doğrulama kırar ve derde gibi üretim. -XX:TieredStopAtLevel=1Bir uygulamayı kısa bir süre (birkaç saniye) çalıştırırsanız sorun değil, aksi takdirde JVM'ye uzun süreli optimizasyonlar sağlayacağı için daha az verimli olacaktır.
loicmathieu

3
oracle doktor Use of -Xverify:none is unsupported.ne anlama geldiğini listeler ?
sakura

1
Pek çok havuz (Oracle UCP elbette ama benim testlerimde de Hikari ve Tomcat) havuzdaki verileri şifreliyor. Aslında bağlantı bilgilerini mi şifreliyorlar yoksa akışı mı kaydırıyorlar bilmiyorum. Her şeye rağmen, şifreleme rasgele sayı üretimini kullanır ve bu nedenle yüksek düzeyde kullanılabilir, yüksek verimli bir entropi kaynağına sahip olmak performansta gözle görülür bir fark yaratır.
Daniel

19

Spring Boot 2.2.M1 , Spring Boot'da Lazy Initialization'ı desteklemek için özellik ekledi.

Varsayılan olarak, bir uygulama içeriği yenilenirken, bağlamdaki her çekirdek oluşturulur ve bağımlılıkları enjekte edilir. Bunun aksine, bir fasulye tanımı tembel olarak başlatılacak şekilde yapılandırıldığında, oluşturulmayacak ve bağımlılıkları ihtiyaç duyulana kadar enjekte edilmeyecektir.

Tembel Başlatma etkinleştirilmesi Set spring.main.lazy-initializationiçin gerçek

Geç Başlatma Ne Zaman Etkinleştirilir

tembel başlatma, başlatma süresinde önemli iyileştirmeler sağlayabilir, ancak bazı önemli dezavantajlar da vardır ve dikkatli bir şekilde etkinleştirmek önemlidir.

Daha fazla ayrıntı için lütfen Belgeye bakın


3
tembel başlatmayı etkinleştirirseniz, ilk yükleme süper hızlıdır, ancak istemci ilk kez erişirken biraz gecikme fark edebilir. Bunu üretim için değil geliştirme için gerçekten tavsiye ediyorum.
Isuru Dewasurendra

@IsuruDewasurendra'nın önerdiği gibi, haklı olarak önerilen bir yol değil, uygulama yük sunmaya başladığında gecikmeyi önemli ölçüde artırabilir.
Narendra Jaggi

Sadece kutuyu yolun aşağısına fırlatır.
Abhijit Sarkar

10

Bu soruda / cevapta açıklandığı gibi, bence en iyi yaklaşım, yalnızca ihtiyacınız olduğunu düşündüklerinizi eklemek yerine, ihtiyacınız olmadığını bildiğiniz bağımlılıkları hariç tutmaktır.

Görmek: Spring Boot Başlangıç ​​Süresini En Aza İndirin

Özetle:

Kapakların altında neler olup bittiğini görebilir ve uygulamayı komut satırından başlatırken --debug belirtmek kadar basit hata ayıklama günlüğünü etkinleştirebilirsiniz. Ayrıca application.properties dosyanızda debug = true belirtebilirsiniz.

Ayrıca, application.properties dosyasında günlük kaydı düzeyini şu kadar basit bir şekilde ayarlayabilirsiniz:

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

İstemediğiniz otomatik yapılandırılmış bir modül tespit ederseniz, devre dışı bırakılabilir. Bunun için dokümanlar burada bulunabilir: http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-disunning-specific-auto-configuration

Bir örnek şöyle görünür:

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

4

Burada açıklanan olası eylemlerin tam listesi var: https://spring.io/blog/2018/12/12/how-fast-is-spring

Bahar tarafındaki en önemli notları koyacağım (biraz düzeltilmiş):

  • Spring Boot web başlangıçlarından sınıf yolu istisnaları:
    • Hazırda Bekletme Doğrulayıcısı
    • Jackson (ancak Spring Boot aktüatörleri buna bağlı). JSON oluşturmaya ihtiyacınız varsa Gson kullanın (yalnızca kutudan çıktığı gibi MVC ile çalışır).
    • Geri oturum açma: bunun yerine slf4j-jdk14 kullanın
  • Yay bağlamı dizinleyicisini kullanın. Fazla bir şey katmayacak ama her küçük yardımcı oluyor.
  • Ödeyemiyorsanız aktüatör kullanmayın.
  • Spring Boot 2.1 ve Spring 5.1'i kullanın. Kullanılabilir olduklarında 2.2 ve 5.2'ye geçin.
  • Spring Boot yapılandırma dosyalarının konumunu spring.config.location(komut satırı bağımsız değişkeni veya Sistem özelliği vb.) İle düzeltin . IDE'de test etme örneği:spring.config.location=file://./src/main/resources/application.properties .
  • İhtiyacınız yoksa JMX'i kapatın spring.jmx.enabled=false(bu, Spring Boot 2.2'de varsayılandır)
  • Fasulye tanımlarını varsayılan olarak tembel yapın. spring.main.lazy-initialization=trueSpring Boot 2.2'de yeni bir bayrak var ( LazyInitBeanFactoryPostProcessoreski Spring için kullanın ).
  • Yağ kavanozunu paketinden çıkarın ve açık bir sınıf yolu ile çalıştırın.
  • JVM'yi ile çalıştırın -noverify. Ayrıca şunu da göz önünde bulundurun -XX:TieredStopAtLevel=1(bu, kaydedilen başlatma süresi pahasına daha sonra JIT'yi yavaşlatacaktır).

Bahsedilenler LazyInitBeanFactoryPostProcessor( spring.main.lazy-initialization=trueİlkbahar 2.2'den itibaren mevcut olan bayrağı uygulayamıyorsanız, Bahar 1.5 için kullanabilirsiniz ):

public class LazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

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

Ayrıca fasulye başlatma zamanını analiz etmek için bir şey kullanabilir (veya kendi başınıza yazabilirsiniz - basit): https://github.com/lwaddicor/spring-startup-analysis

Umarım yardımcı olur!


0

Benim durumumda çok fazla kırılma noktası vardı. "Kesme Noktalarını Sustur" seçeneğine tıkladığımda ve uygulamayı hata ayıklama modunda yeniden başlattığımda, uygulama 10 kat daha hızlı başladı.


-1

El ile test için geliştirme dönüşünü optimize etmeye çalışıyorsanız, devtools kullanımını şiddetle tavsiye ederim .

Spring-boot-devtools kullanan uygulamalar, sınıf yolundaki dosyalar her değiştiğinde otomatik olarak yeniden başlayacaktır.

Sadece yeniden derleyin - ve sunucu kendini yeniden başlatır (Groovy için yalnızca kaynak dosyayı güncellemeniz gerekir). Bir IDE kullanıyorsanız (örn. 'vscode'), java dosyalarınızı otomatik olarak derleyebilir, böylece sadece bir java dosyasını kaydetmek, dolaylı olarak sunucuyu yeniden başlatabilir - ve Java bu açıdan Groovy kadar kusursuz hale gelir.

Bu yaklaşımın güzelliği, artımlı yeniden başlatmanın bazı sıfırdan başlatma adımlarını kısa devre yapmasıdır - bu nedenle hizmetiniz çok daha hızlı bir şekilde yedeklenecek ve çalışmaya başlayacaktır!


Maalesef bu, dağıtım veya otomatik birim testi için başlatma sürelerine yardımcı olmuyor.


-1

UYARI: Otomatik DB şema üretimi için Hazırda Bekletme DDL'yi kullanmıyorsanız ve L2 önbelleği kullanmıyorsanız, bu yanıt sizin için geçerli DEĞİLDİR. İleri kaydırın.

Bulduğum sonuç, Hazırda Bekletme'nin uygulama başlangıcına önemli ölçüde zaman kattığı yönünde. L2 önbelleğini ve veritabanı başlatmayı devre dışı bırakmak , Spring Boot uygulamasının daha hızlı başlatılmasını sağlar. Üretim için önbelleği AÇIK bırakın ve geliştirme ortamınız için devre dışı bırakın.

application.yml:

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

Test sonuçları:

  1. L2 önbelleği AÇIK ve 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 önbelleği KAPALI ve 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)

Şimdi tüm bu boş zamanlarla ne yapacağımı merak ediyorum


hibernate.hbm2ddl.auto = güncellemenin l2 önbelleğiyle ilgisi yoktur. ddl .. = update, mevcut veritabanı şemasını taramayı ve şemayı varlıklarınızı yansıtacak şekilde güncellemek için gerekli sql'yi hesaplamayı belirtir. 'Hiçbiri' bu doğrulamayı yapmaz (ayrıca şemayı güncellemeye çalışmaz). En iyi uygulamalar, şema değişikliklerinizi yöneteceğiniz ve bunları takip edebileceğiniz sıvı taban gibi bir araç kullanmaktır.
Radu Toader

@RaduToader bu soru ve cevabım Spring Boot başlangıç ​​süresini hızlandırmakla ilgili. Hibernate DDL ve Liquibase tartışmasıyla hiçbir ilgisi yoktur; bu araçların hem artıları hem de eksileri vardır. Demek istediğim, DB şema güncellemesini devre dışı bırakıp yalnızca gerektiğinde etkinleştirebiliriz. Hazırda bekletme, son çalıştırmadan bu yana model değişmese bile başlangıçta önemli ölçüde zaman alır (DB şemasını otomatik oluşturulan şema ile karşılaştırmak için). Aynı nokta L2 önbelleği için de geçerlidir.
naXa

evet, bunu biliyorum, ama demek istediğim, gerçekte ne yaptığını açıklamamanın biraz tehlikeli olduğuydu. DB'nizi çok kolay bir şekilde boş bırakabilirsiniz.
Radu Toader

@RaduToader Cevabımda DB'nin başlatılmasıyla ilgili bir dokümantasyon sayfasına bağlantı vardı. Okudun mu? En popüler araçları (Hazırda Bekletme ve Liquibase, JPA ve Flyway) listeleyen kapsamlı bir kılavuz içerir. Ayrıca bugün cevabımın üstüne net bir uyarı ekliyorum. Sonuçları açıklamak için başka değişikliklere ihtiyacım olduğunu düşünüyor musunuz?
naXa

Mükemmel. Teşekkür ederim
Radu Toader

-3

Daha önce kimsenin bu optimizasyonları önermesini garip buluyorum. Geliştirme sırasında proje oluşturmayı ve başlatmayı optimize etmeye ilişkin bazı genel ipuçları:

  • geliştirme dizinlerini antivirüs tarayıcısından hariç tutun:
    • proje dizini
    • çıktı dizini oluşturun (proje dizininin dışındaysa)
    • IDE indeksleri dizini (örneğin ~ / .IntelliJIdea2018.3)
    • dağıtım dizini (Tomcat'teki web uygulamaları)
  • donanımı yükselt. daha hızlı CPU ve RAM, daha iyi internet bağlantısı (bağımlılıkları indirmek için) ve veritabanı bağlantısı kullanın, SSD'ye geçin. bir ekran kartı önemli değil.

UYARILAR

  1. ilk seçenek, azaltılmış güvenlik fiyatı için gelir.
  2. ikinci seçenek maliyetlidir (tabii ki).

Soru, derleme zamanını değil, önyükleme süresini iyileştirmekle ilgilidir.
ArtOfWarfare

@ArtOfWarfare soruyu tekrar oku. soru problemi "Bu kadar [zaman] almasından, çoğunlukla gelişim akışını bozduğu için mutsuzum" şeklinde ifade eder. Bunun birincil bir sorun olduğunu hissettim ve cevabımda ele aldım.
naXa

-9

Bana göre yanlış bir yapılandırma ayarı kullanıyormuşsunuz gibi geliyor. MyContainer'ı ve olası çakışmaları kontrol ederek başlayın. En çok kaynağı kimin kullandığını belirlemek için, bir seferde her bağımlılık için hafıza haritalarını kontrol etmeniz gerekir (veri miktarını görün!) - ve bu da çok zaman alır ... (ve SUDO ayrıcalıkları). Bu arada: genellikle kodu bağımlılıklara karşı mı test ediyorsunuz?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.