Come riscaldare le classi Java per evitare la prima chiamata lenta?


13

Sto realizzando un progetto in cui ho bisogno che tutte le chiamate API richiedano meno di 1, ma sto affrontando un problema con la prima chiamata per ogni percorso che è più lento di quelli seguenti.

Attualmente la prima chiamata a / login richiede 3.6s e le successive prendono 170ms e lo stesso per tutte le altre rotte.

Ho scoperto che usando -XX:+TraceClassLoadingquello alla prima chiamata, le classi sono state caricate in memoria e ciò ha causato il problema delle prestazioni.

Tuttavia, non ho trovato un modo semplice per caricare tutte le classi all'avvio e per ogni nuovo servizio, ho bisogno di aggiungere una chiamata di riscaldamento in un ApplicationRunner.

Qualcuno ha una soluzione per caricare automaticamente le classi di un'applicazione SpringBoot o riscaldare tutte le sue rotte?


Puoi aggiungere più dettagli? L'applicazione sta istanziando i controller? O stai chiamando altri servizi? Come si effettuano le chiamate verso altri servizi?
Menios,

Spring Boot utilizza intensamente la scansione di classe, quindi non è necessario "riscaldare" nulla di simile all'applicazione desktop. Questo lungo caricamento iniziale potrebbe essere il risultato della ricerca di risorse, ad esempio il caricamento del modello di pagina.
Alex Chernyshev,

Un approccio un po 'indiretto: se si dispone del 100% di copertura unit test per gli endpoint, è possibile utilizzarli. Dovresti comunque codificare per endpoint ma guadagni qualcosa
Marcia del

1
Potrebbe non essere l'ideale a seconda del progetto che stai facendo, ma potresti chiamare i tuoi endpoint internamente quando l'applicazione viene caricata.
omoshiroiii,

@omoshiroiii non c'è niente di sbagliato in questo. noi lo facciamo. in produzione. la ragione ha a che fare con alcune librerie dinamiche che usano invokedynamice sappiamo che la risoluzione è lenta alla prima chiamata per quelle (abbiamo decine di migliaia di tali chiamate, che senza questa prima chiamata si accumulano in decine di secondi).
Eugene,

Risposte:


1

Il caricamento della classe Java è pigro. Ciò significa che una classe viene caricata dalla JVM solo quando è necessario e se necessario.

Se vuoi forzarlo a caricare avidamente le classi devi solo fare riferimento a loro. Un modo per farlo è quello di scorrere i contenuti del vaso o i file di classe per ottenere i nomi delle classi e quindi usarli per chiamare Class.forName(className).

Inoltre, se il tempo di avvio e le prestazioni sono molto importanti per il tuo caso d'uso, potresti voler esaminare in anticipo soluzioni di compilazione come GraalVM o ridurre la soglia di JIT per la compilazione ( -XX:CompileThreshold).


nessuno di questi risolverà il problema di OP. il caricamento è ancora pigro in GraalVM ed JITè insignificante per le prime invocazioni, davvero.
Eugene,

inoltre, GraalVMva bene, ma per favore dai un'occhiata al numero di problemi che ha in github: non appena passi da un progetto sandbox a qualcosa di più grande (ti guardo principalmente riflesso), avrai un po 'di dolore, almeno. il mio punto è: passare a GraalVM non è un semplice schiocco di dita.
Eugene,

Ho pensato di caricare le lezioni nel vaso ma non ho trovato il modo di farlo, avresti un esempio?
Ybri,

@Eugene se leggi la mia risposta vedrai che non ho detto GraalVM o la soglia JIT cambierebbe la pigrizia del caricamento della classe. La risposta alla domanda di OP sulla pigrizia è il paragrafo precedente a quello. L'ultimo paragrafo è solo un suggerimento aggiuntivo nel caso in cui OP debba ottimizzare ulteriormente i tempi / le prestazioni di avvio oltre il caricamento della classe.
andresp

1
@Ybri ci sono altre domande con risposte a questa qui, ad esempio, stackoverflow.com/questions/2370867/...
andresp

0

Per me, l'unica opzione praticabile che hai è class data sharing, diffusa tra JEP 310 , JEP 341 e JEP 350 , ma questo richiede molto probabilmente java-13. Lo stiamo testando internamente sul mio posto di lavoro (principalmente per divertimento, non mentirò) e i risultati sembrano buoni, finora.

L'altra opzione sta chiamando i tuoi endpoint all'avvio dell'applicazione, se questa è un'opzione. Ancora una volta, è per noi ad esempio: li chiamiamo con dati fittizi un paio di centinaia di volte per riscaldare il codice. Allo stesso tempo, abbiamo servizi in cui ciò sarebbe impossibile - ecco perché anche l'esplorazione CDS.


Come gestite l'autenticazione e gli endpoint post per evitare la creazione di dati nel database di produzione?
Ybri,

@Ybri esattamente perché l'ho detto, impossibile per alcuni.
Eugene,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.