En este tutorial continuaremos conociendo Quarkus, utilizaremos contenedores y GraalVM para sacar el máximo rendimiento.
Índice de contenidos
- 1. Introducción
- 2. Entorno
- 3. Prerrequisitos
- 4. Probando Quarkus y GraalVM
- 5. Quarkus con compilación nativa
- 6. Juntemos todo a ver qué pasa
- 7. Conclusiones
- 8. Referencias
1. Introducción
En el anterior tutorial pudimos ver las bondades que nos ofrece Quarkus para el desarrollo de servicios ligeros. Pudimos hacer algunas mediciones y observar si mejoramos algo.En este tutorial nos centraremos en mejorar estos tiempos utilizando la compilación nativa y el uso de contenedores.
Comencemos.
2. Entorno
El tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil MacBook Pro 15 pulgadas (2.3 GHz Intel i9, 32GB 2400 Mhz DDR4, 1 TB Flash Storage).
- Sistema Operativo: MacOs Catalina 10.15.2
- Entorno de desarrollo: IntelliJ IDEA 2019.3.1
- Apache Maven 3.6.3
- Quarkus 1.1.1.Final
- GraalVM 19.2.1 C.E (basado en OpenJDK 8)
- Docker 19.03.5
3. Prerrequistos
Quarkus incorpora en sus guías la documentación necesaria para que podáis instalaros los componentes necesarios. Para este tutorial necesitaremos:
- Entorno de desarrollo para C
- Docker
- GraalVM 19.2
3.1. Entorno de desarrollo para C
Para la compilación nativa hace falta disponer de estas librerías. En el caso de Linux, hace falta un GCC, las librerías glibc y cabeceras zlib.
# dnf (rpm-based) sudo dnf install gcc glibc-devel zlib-devel libstdc++-static # Debian-based distributions: sudo apt-get install build-essential libz-dev zlib1g-dev
En el caso de masOS, XCode proporciona las dependencias necesarias.
xcode-select --install
3.2. Docker
La mayoría de vosotros ya conocéis Docker pero si no fuese el caso, disponéis de estupendos tutoriales en esta misma web.
3.3. GraalVM 19.2
A este apartado podríamos dedicarle un tutorial completo, es un proyecto de Oracle que hasta hace poco (mayo 2019) no ha publicado su primera versión lista para producción. Si bien, es muy amplio, si nos ceñimos a la definición podemos leer:
«GraalVM es una máquina virtual universal para ejecutar aplicaciones escritas en JavaScript, Python, Ruby, R, lenguajes basados en JVM como Java, Scala, Groovy, Kotlin, Clojure y lenguajes basados en LLVM como C y C ++.
GraalVM elimina el aislamiento entre lenguajes de programación y permite la interoperabilidad en un tiempo de ejecución compartido. Puede ejecutarse de forma independiente o en el contexto de OpenJDK, Node.js u Oracle Database.»
Actualmente se habla mucho de GraalVM y no es para menos ya que muchos lenguajes, frameworks se hayan adherido y tienen actualmente soporte para la misma.
Al ser un producto dependiente del entorno en que se ejecuta, hay diferentes versiones. En nuestro caso hemos instalado la versión de macOS para una openJDK 8. Disponéis de una completa documentación sobre su instalación en su web.
4. Probando Quarkus y GraalVM
Vamos a probar de nuevo nuestro servicio con Quarkus pero utilizando GraalVm para observar la posible mejora. En este caso, no hace falta que realicemos modificaciones en nuestro servicio, basta con apuntar a la nueva máquina virtual.
export GRAALVM_HOME=/ruta_a_graalvm export JAVA_HOME=$GRAALVM_HOME/Contents/Home $JAVA_HOME/bin/java -jar target/filmoteca-quarkus-1.0-SNAPSHOT-runner.jar
Arranque con GraalVM
Tiempo de la primera petición con GraalVM
Como podemos ver, los tiempos con respecto al tutorial anterior se ha reducido un poco más sin tocar nuestro componente jar. Vamos a incorporar la compilación nativa en esta ecuación para sacarle el máximo provecho al hardware que tenemos.
5. Quarkus con compilación nativa
Aprovechando las posibilidades que proporciona GraalVM y Quarkus vamos a ejecutar nuestro servicio de forma nativa.
./mvnw package -Pnative
En este caso, el plugin de Quarkus ha incluido una fase adicional para el compilado nativo y los tiempos de compilación se han incrementado. En la carpeta target, ahora podéis observar cómo ha creado un nuevo ejecutable que incorpora todo lo necesario para la ejecución de nuestro servicio REST. Al ejecutarlo se puede observar:
Arranque con compilación nativa
Como veis, los tiempos ahora son realmente bajos. Esto se debe a que es un ejecutable nativo al entorno, en este caso para mac. Este enfoque tiene la pequeña pega que no es portable entre entornos (nuestros servidores pueden estar en cualquier plataforma). Aquí es donde entra en acción el soporte a contenedores.
6. Juntemos todo a ver qué pasa
Hasta ahora hemos probado cada herramienta de forma independiente para ver lo que nos aporta cada una de ellas. Ahora vamos a preparar una versión nativa para un contenedor de docker y juntar todas las piezas.
./mvnw package -Pnative -Dquarkus.native.container-build=true docker build -f src/main/docker/Dockerfile.native -t quarkus/filmoteca-quarkus . docker run -i --rm -p 8080:8080 quarkus/filmoteca-quarkus
Este paquetizado genera un ejecutable nativo para linux de 64 bits. Esto no supone un problema porque a continuación se va a transferir a un contenedor docker que contiene una imagen de linux que “entiende” este ejecutable.
Por último arrancamos nuestro contenedor con nuestra API REST.
Tiempo de arranque de la versión “dockerizada”
Tiempo de la primera petición al servicio
Como se puede observar los tiempos son muy bajos, nuestro servicio está “dockerizado” y es un ejecutable nativo para la imagen docker.
Si atendemos al tiempo de primera petición y tamaño también son muy bajos. El tamaño de la imagen docker también es muy bajo.
7. Conclusiones
La combinación de todas estas tecnologías nos están llevando hacia servicios cada vez más ligeros y optimizados en un contexto de contenedores. Aún están en una fase temprana porque acaban de sacar las primeras versiones para un entorno productivo pero habrá que estar atentos a su futura evolución.
Espero que os sea de utilidad.
8. Referencias
- Documentación de Quarkus.
- Documentación de GraalVM.
- Código fuente de la version con Quarkus. https://github.com/ajmorgang/filmoteca-quarkus