Wie wärme ich Java-Klassen auf, um einen langsamen ersten Anruf zu vermeiden?

13

Ich mache ein Projekt, bei dem alle API-Aufrufe weniger als 1 Sekunde dauern müssen, aber ich habe ein Problem mit dem ersten Aufruf jeder Route, die langsamer ist als die folgenden.

Derzeit dauert der erste Anruf bei / login 3,6 s und der nächste 170 ms und für alle anderen Routen gleich.

Ich fand heraus, -XX:+TraceClassLoadingdass beim ersten Aufruf die Klassen in den Speicher geladen wurden und dies das Leistungsproblem verursachte.

Ich habe jedoch keine einfache Möglichkeit gefunden, alle Klassen beim Start zu laden, und für jeden neuen Dienst muss ich einen Aufwärmaufruf in einem ApplicationRunner hinzufügen.

Hat jemand eine Lösung, um die Klassen einer SpringBoot-Anwendung automatisch zu laden oder alle Routen aufzuwärmen?

Ybri
quelle
Können Sie weitere Details hinzufügen? Instanziiert Ihre Anwendung Controller? Oder rufen Sie andere Dienste an? Wie telefonieren Sie mit anderen Diensten?
Menios
Spring Boot verwendet das Scannen von Klassen intensiv, sodass Sie nichts wie bei einer Desktop-Anwendung aufwärmen müssen. Dieses lange anfängliche Laden kann das Ergebnis einer Ressourcensuche sein - zum Beispiel das Laden von Seitenvorlagen.
Alex Chernyshev
Ein bisschen indirekter Ansatz: Wenn Sie eine 100% ige Unit-Test-Abdeckung für die Endpunkte haben, können Sie diese verwenden. Sie müssten immer noch pro Endpunkt codieren, aber Sie erhalten etwas
Marged
1
Je nach aktuellem Projekt ist dies möglicherweise nicht ideal, aber Sie können Ihre Endpunkte intern aufrufen, wenn Ihre Anwendung geladen wird.
Omoshiroiii
@omoshiroiii daran ist nichts auszusetzen. wir machen es. in Produktion. Der Grund hat mit einigen dynamischen Bibliotheken zu tun, die verwendet werden, invokedynamicund wir wissen, dass die Auflösung beim ersten Aufruf für diese langsam ist (wir haben Zehntausende solcher Aufrufe, die sich ohne diesen ersten Aufruf auf Zehntelsekunden summieren).
Eugene

Antworten:

1

Das Laden von Java-Klassen ist faul. Dies bedeutet, dass eine Klasse nur dann von der JVM geladen wird, wenn dies erforderlich ist und erforderlich ist.

Wenn Sie es erzwingen möchten, Klassen eifrig zu laden, müssen Sie sie nur referenzieren. Eine Möglichkeit besteht darin, den JAR-Inhalt oder die Klassendateien zu durchlaufen, um die Klassennamen abzurufen und sie dann zum Aufrufen zu verwenden Class.forName(className).

Wenn die Startzeit und die Leistung für Ihren Anwendungsfall sehr wichtig sind, sollten Sie sich vorab mit Kompilierungslösungen wie GraalVM befassen oder den JIT-Schwellenwert für die Kompilierung verringern ( -XX:CompileThreshold).

andresp
quelle
Keiner von beiden wird das Problem von OP lösen. Das Laden ist in GraalVM immer noch faul und JITbei den ersten Aufrufen wirklich bedeutungslos .
Eugene
auch GraalVMgut, aber bitte in GitHub hat einen Blick auf die Reihe von Fragen haben: sobald Sie von einem Sandbox - Projekt zu etwas gehen größer (ich bin auf der Suche Sie Reflexion, vor allem), können Sie in einem gewissen Schmerz sein wird, mindestens. Mein Punkt ist: Das Wechseln zu GraalVM ist kein einfaches Fingerschnippen.
Eugene
Ich habe darüber nachgedacht, die Klassen in das Glas zu laden, aber ich habe keinen Weg gefunden, dies zu tun. Hätten Sie ein Beispiel?
Ybri
@Eugene Wenn Sie meine Antwort lesen, werden Sie sehen, dass ich nicht gesagt habe, dass GraalVM oder der JIT-Schwellenwert die Faulheit des Klassenladens ändern würden. Die Antwort auf die Frage von OP bezüglich Faulheit ist der vorstehende Absatz. Der letzte Absatz ist nur ein zusätzlicher Tipp für den Fall, dass OP die Startzeit / Leistung über das Laden der Klasse hinaus weiter optimieren muss.
andresp
1
@Ybri gibt es hier andere Fragen mit Antworten darauf, zB stackoverflow.com/questions/2370867/…
andresp
0

Für mich ist die einzige praktikable Option, die Sie haben class data sharing, über JEP 310 , JEP 341 und JEP 350 verteilt , aber dies erfordert höchstwahrscheinlich Java-13. Wir testen dies intern an meinem Arbeitsplatz (meistens zum Spaß, um nicht zu lügen) und die Ergebnisse sehen bisher gut aus.

Die andere Option ist das Aufrufen Ihrer Endpunkte beim Start der Anwendung - sofern dies eine Option ist. Auch hier ist es ist für uns zum Beispiel: wir sie mit Dummy - Daten , die ein paar hundert Mal den Code , um sich aufzuwärmen nennen. Gleichzeitig haben wir aber Dienste, bei denen dies unmöglich wäre - deshalb auch das Erkunden von CDS.

Eugene
quelle
Wie gehen Sie mit der Authentifizierung und den Post-Endpunkten um, um die Erstellung von Daten in Ihrer Produktionsdatenbank zu vermeiden?
Ybri
@ Ybri genau warum ich sagte, für manche unmöglich .
Eugene