Spring Boot Vs Quarkus – La batalla va a empezar
Spring actualmente es el framework de referencia en la construcción e implementación de microservicios. Este corre en la JVM y nos ofrece muchas posibilidades de integración y de desarrollo. Por otro lado tenemos Quarkus, que une un conjunto de tecnologías open source adaptadas a GraalVM y HotSpot, para desarrollar aplicaciones Java, las cuales nos ofrecen un bajo consumo de memoria y un muy buen tiempo de arranque. En esta nueva entrada de refactorizando Spring Boot Vs Quarkus – La batalla va a empezar, vamos a ver y analizar los tiempos de arranque y el consumo de memoria, entre Quarkus y Spring Boot.
Aunque Java sigue siendo uno de los lenguajes predominantes, siempre has estado de manifiesto sus problemas de rendimiento. Esto ha sido en parte debido a las capas de abstracción que existen entre el código y la máquina, con una JVM que hace las veces de máquina real. Este es el coste a pagar por tener un lenguaje multiplataforma.
Comenzando la lucha
A continuación vamos a comparar dos aplicaciones diferentes, una en Quarkus y otra en Spring Boot.
Vamos a lanzar ambas aplicaciones varias veces, creando y destruyendo los contenedores y ver que están ejecutándose y funcionando correctamente y a comparar el tiempo de arranque y los consumos de memoria.
Quarkus – Oponente 1
Tal y como comentamos en una entrada anterior Quarkus es un framework de Java nativo para Kubernetes, cuyo principal objetivo es funcionar bajo kubernetes y en un entorno sin servidor. A diferencia de otros frameworks de Java, Quarkus funciona bajo GraalVM y HotSpot.
A continuación vamos a partir del ejemplo que hicimos en los primeros pasos con Quarkus, para poder tener una aplicación lista en un contenedor. La puedes descargar de github desde aquí. En el link anterior se explican todos y cada uno de los pasos necesarios para poder arrancar el proyecto de Quarkus.
Spring Boot – Oponente 2
Spring Boot es el framework actual de facto en el desarrollo de microservicios y trabaja bajo la JVM.
Para seguir, vamos a necesitar construir y arrancar una imagen docker de nuestra aplicación Spring Boot que devolverá un simple Hello World cuando se llame a un controlador, para tener que así sea igual que el proyecto de Quarkus que tenemos, aquí puedes encontrar un ejemplo.
En este caso no explicamos en el repositorio como poder contenerizar y arrancar una imagen docker del proyecto así que vamos a ello:
Crear fichero Dockerfile:
FROM openjdk:11.0-jre ADD target/spring-boot-0.0.1-SNAPSHOT.jar app.jar ENV JAVA_OPTS="" ENTRYPOINT exec java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999 -jar /app.jar
Construir la imagen:
docker build -t spring-boot:0.0.1-SNAPSHOT .
Arrancar la imagen:
docker run -p 8080:8080 spring-boot:0.0.1-SNAPSHOT
Fight!
Tiempos de arranque
Siempre los tiempos de arranque son importantes, pero cuando nos encontramos en entornos cloud o en arquitecturas Serverless cobran una mayor relevancia. Por ejemplo, cuando queremos escalar un servicio debido a una fuerte demanda, el tiempo de arranque será de vital importancia.
En el gráfico se puede ver como la aplicación con Quarkus nativo arranca en un timpo muy muy inferior al de Spring Boot (el tiempo de Quarqus es inapreciable), incluso si probamos haciendolo con una imagen generada con JVM, es también bastante inferior. Con esto vemos, como los tiempos haciendo uso de Quarkus en modo nativo son increíblemente buenos, con esto, queda claro que Quarkus ha sido desarrollado con ese objetivo, ser un framework de Java nativo para Kubernetes y entornos contenerizados.
And the winner is Quarkus
Consumo de memoria
Al igual que hemos comparado los tiempos de arranque haciendo uso de Quarkus con JVM y con GraalVM, vamos a mirar ahora el consumo de memoria de los contenedores, siempre en el momento de arranque:
And the winner is Quarkus otra vez….
Consumo de CPU
En este caso vamos a ver los consumos de CPU de los contenedores en los arranques.
En este caso entre Quarkus JVM y Spring Boot apenas hemos visto diferencia en el uso de CPU, pero cuando utilizamos la imagen nativa de Quarkus el consumo es considerablemente más bajo que con el resto, el consumo en porcentaje de CPU baja drásticamente.
And the winner is Quarkus nativo
Conclusión
Como hemos visto Quarkus ha ganado en todos los escenarios, pero no por ello podríamos decir que Quarkus debería ser el framework de referencia. Antes de poder tomar la decisión habría que hacer más pruebas en entornos y con cargas reales, cómo funcionaría en varios pods etc.
Además, en entornos de cloud uno de los problemas subyacentes es el tema de Cold Start, y habría que ver como se comporta ante estos escenarios, por ejemplo en un mundo serverless:
- La función se ha implementado pero todavía no se ha activado.
- La función ha estado inactiva el tiempo suficiente para que el proveedor de la función elimine los recursos que se han utilizado durante la última llamada.
- Vamos a escalar la función para aumentar la capacidad creando nueva instancia.
Podríamos decir en líneas generales que en cuenta métricas hemos visto un mejor uso de los recursos, tanto en tiempos de arranque, como memoria y uso de CPU, sobre todo cuando se hace una creación de imagen nativa ya que se compila el código en la instrucción de la CPU, en lugar del código de bytes de la JVM.
¿Has podido hacer pruebas entre ambos en entornos reales?
Otros artículos que te pueden interesar
Ejemplo de aplicación de Spring Boot y Kubernetes
Usando el ServiceAccount en Kubernetes