Spring Boot 3
Nuestros Hunters siguen trayéndonos más novedades tecnológicas. En esta ocasión, nos hablan de Spring Boot 3 y la compilación nativa de proyectos, una de sus principales novedades.
Las compilaciones nativas producen un código ejecutable en una arquitectura concreta, sin la necesidad de utilizar la máquina virtual java, permitiendo una mayor velocidad de ejecución y un menor uso de recursos.
Al compilar proyectos de forma nativa, se realiza un preprocesamiento en tiempo de compilación que resuelve configuraciones que normalmente se establecen durante la iniciación del proyecto en tiempo de ejecución. Además, se realizan optimizaciones como la eliminación de código no utilizado, lo que permite un inicio mucho más rápido, un mayor rendimiento y menor uso de recursos.
A través de esto, se genera directamente una imagen Docker basada en GraalVM, sistema ideado para la ejecución de programas java con alto rendimiento.
La compilación nativa es especialmente útil en un entorno serverless con funciones como servicio, donde se cuenta con recursos limitados y se requiere una inicialización rápida.
Testeando proyectos
Tras compilar un mismo proyecto de forma nativa y estándar se han obtenido los siguientes datos:
Compilación de datos de proyectos en forma nativa y estándar.
Limitaciones y compatibilidades
Durante las compilaciones nativas Spring se inicializan las configuraciones del proyecto, fijándose el classpath y estableciendo los beans que se inyectarán de forma estática, haciendo imposible su modificación en tiempo de ejecución.
Adicionalmente, la utilización de GraalVM limita el uso de herramientas como la reflexión, siendo necesario indicarla explícitamente con el fin de que se procese en tiempo de compilación.
Debido a esto es importante tener en cuenta las limitaciones presentes en las compilaciones nativas antes de integrarlas dentro de un proyecto.
Integración en un proyecto
Para compilar un proyecto de forma nativa es suficiente con añadir un plugin dentro del proyecto:
Una vez añadido el plugin necesario, se puede compilar el proyecto con el siguiente comando:
Cuando finalice la compilación se habrá creado una imagen Docker con un tag con el formato “artifactId:version”.
Inicialización
Se ha compilado y ejecutado un mismo servicio web mediante compilación nativa y estándar y se han obtenido los siguientes datos durante la inicialización:
Tiempos de inicialización:
- Versión nativa: 1 segundo
- Versión estándar: 14 segundos
Gracias a que en la versión nativa la configuración se ha realizado en tiempo de compilación, esta no ha requerido uso de CPU para su inicialización y su uso de memoria RAM ha sido constante desde el principio. Comparado con la versión estándar que ha requerido la utilización de CPU de forma inicial y de tiempo para su inicialización.
Pruebas ejecución trabajo en lote
Se realizan pruebas sobre un programa Command Line Runner. Estas pruebas consisten en una consulta y en una inserción a una base de datos por cada iteración. Mencionar que las operaciones se realizan mediante Hibernate.
Se ejecuta esta prueba con 5.000 iteraciones y 200.000 iteraciones, obteniendo los siguientes resultados:
Con los siguientes tiempos de ejecución:
- Nativa con 5000 iteraciones: 11s (0.29s inicialización, 8s ejecución)
- Estándar con 5000 iteraciones: 23s (9s inicialización, 12s ejecución)
- Nativa con 200000 iteraciones: 375s (0.26s inicialización, 372s ejecución)
- Estándar con 200000 iteraciones: 160s (9s inicialización, 147s ejecución)
Se puede observar que la versión nativa destaca en trabajos cortos, donde el tiempo de inicialización es más significativo, ejecutándose en un menor tiempo con un menor uso de recursos.
Por lo contrario, en ejecuciones largas la versión nativa tarda un tiempo considerablemente mayor en su ejecución, pese a tener un consumo menor de recursos estos se utilizan durante más tiempo por lo que no ofrece una ventaja.
Pruebas estrés servicio web
Se realizan pruebas de estrés sobre una aplicación web sencilla, con 50 hilos se realiza 3 repeticiones por hilo 50 peticiones GET y 50 peticiones POST creando una entidad por cada una, con un tiempo de espera de 300ms entre iteraciones.
Como se puede observar, la versión nativa ha utilizado considerablemente una menor cantidad de memoria RAM durante toda la ejecución y una cantidad menor de CPU al inicio.
En cuanto al tiempo de respuesta, ocurre una situación similar a la observada en la ejecución de un trabajo en lote, la versión nativa ofrece considerablemente un mayor rendimiento en el inicio de la ejecución, pero según se avanza este rendimiento decae mientras que el rendimiento de la versión estándar mejora.
¿Cuáles son los pros y contras de la compilación nativa?
Pros
- Menor uso de RAM y CPU.
- Menor tamaño de imagen.
- Inicialización instantánea.
- Código no utilizado se elimina durante la compilación.
- Menor tiempo de ejecución durante ejecuciones cortas.
Contras
- Tiempo de compilación elevado.
- Classpath estático.
- Resolución de Beans en tiempo de compilación.
- Incompatibilidades inherentes a GraalVM con ciertas librerías y herramientas.
¿Qué podemos concluir?
Como se ha observado en las pruebas realizadas, las compilaciones nativas en Spring están especialmente indicadas para ejecuciones con un tiempo de ejecución reducido, consumiendo considerablemente menos recursos y con un tiempo de inicialización prácticamente inexistente
Estas ventajas pierden peso cuando la ejecución se alarga en el tiempo ya que el rendimiento se deteriora conforme avanza la ejecución, mientras que en comparación la versión estándar mejora su rendimiento conforme avanza la ejecución.
¿Quieres saber más sobre Hunters?
Ser un hunter es aceptar el reto de probar nuevas soluciones que aporten resultados diferenciales. Únete al programa Hunters y forma parte de un grupo transversal con capacidad de generar y transferir conocimiento.
Anticípate a las soluciones digitales que nos harán crecer. Consulta más información sobre Hunters en la web.