¿Cómo calentar las clases de Java para evitar la primera llamada lenta?

13

Estoy haciendo un proyecto en el que necesito que todas las llamadas a la API tarden menos de 1s, pero tengo un problema con la primera llamada a cada ruta que es más lenta que las siguientes.

Actualmente, la primera llamada / inicio de sesión dura 3.6 segundos y las siguientes tardan 170 ms y lo mismo para todas las demás rutas.

Descubrí que usando -XX:+TraceClassLoadingeso en la primera llamada, las clases se cargaron en la memoria y eso causó el problema de rendimiento.

Sin embargo, no encontré una manera fácil de cargar todas las clases al inicio y para cada nuevo servicio, necesito agregar una llamada de calentamiento en un ApplicationRunner.

¿Alguien tiene una solución para cargar automáticamente las clases de una aplicación SpringBoot o calentar todas sus rutas?

Ybri
fuente
¿Puedes agregar más detalles? ¿Su aplicación está instalando controladores? ¿O estás llamando a otros servicios? ¿Cómo haces las llamadas a otros servicios?
Menios
Spring Boot usa el escaneo de clase de manera intensiva, por lo que no necesita 'calentar' nada como en una aplicación de escritorio. Esta larga carga inicial podría ser el resultado de la búsqueda de recursos, por ejemplo, la carga de plantillas de página.
Alex Chernyshev
Un enfoque indirecto: si tiene una cobertura de prueba de unidad del 100% para los puntos finales, podría usarlos. Todavía tendría que codificar por punto final, pero gana algo
Marcado
1
Puede que no sea lo ideal según el proyecto que esté realizando, pero podría llamar a sus puntos finales internamente cuando se cargue su aplicación.
omoshiroiii
@omoshiroiii no hay nada de malo en eso. nosotros lo hacemos. en producción. la razón tiene que ver con algunas bibliotecas dinámicas que usan invokedynamicy sabemos que la resolución es lenta en la primera llamada para esas (tenemos decenas de miles de esas llamadas, que sin esta primera llamada se acumulan en decenas de segundos).
Eugene

Respuestas:

1

La carga de clases de Java es perezosa. Esto significa que JVM solo carga una clase cuando lo necesita y si lo necesita.

Si desea forzarlo a cargar clases ansiosamente, solo necesita hacer referencia a ellas. Una forma de hacerlo es recorrer el contenido del jar o los archivos de clase para obtener los nombres de clase y luego usarlos para llamar Class.forName(className).

Además, si el tiempo de inicio y el rendimiento son muy importantes para su caso de uso, es posible que desee buscar soluciones de compilación anticipadas como GraalVM , o reducir el umbral de compilación de JIT ( -XX:CompileThreshold).

andresp
fuente
ninguno de esos resolverá el problema de OP. la carga aún es lenta en GraalVM y no JITtiene sentido en las primeras invocaciones, realmente.
Eugene
Además, GraalVMes bueno, pero eche un vistazo a la cantidad de problemas que tiene en Github: tan pronto como pase de un proyecto de caja de arena a algo más grande (estoy mirando su reflejo, principalmente), sentirá algo de dolor, al menos. mi punto es: cambiar a GraalVM no es un simple chasquido de dedos.
Eugene
Pensé en cargar las clases en el frasco pero no encontré una manera de hacerlo, ¿tendrías un ejemplo?
Ybri
@Eugene si lees mi respuesta, verás que no dije GraalVM o que el umbral JIT cambiaría la pereza de la carga de clases. La respuesta a la pregunta de OP con respecto a la pereza es el párrafo anterior. El último párrafo es solo un consejo adicional en caso de que OP necesite optimizar aún más el tiempo de inicio / rendimiento más allá de la carga de clase.
andresp
1
@Ybri hay otras preguntas con respuestas a eso aquí, por ejemplo stackoverflow.com/questions/2370867/…
andresp
0

Para mí, la única opción viable que tienes es class data sharing, distribuir entre JEP 310 , JEP 341 y JEP 350 , pero esto requiere java-13 muy probablemente. Estamos probando esto internamente en mi lugar de trabajo (principalmente por diversión, no para mentir) y los resultados se ven bien, hasta ahora.

La otra opción es llamar a sus puntos finales cuando se inicia la aplicación, si esa es una opción. Nuevamente, es para nosotros, por ejemplo: los llamamos con datos ficticios un par de cientos de veces para calentar el código. Pero, al mismo tiempo, tenemos servicios donde esto sería imposible, es por eso que CDStambién exploramos.

Eugene
fuente
¿Cómo maneja la autenticación y los puntos finales de publicación para evitar la creación de datos en su base de datos de producción?
Ybri
@Ybri exactamente por qué dije, imposible para algunos.
Eugene