¿Qué es Quarkus?

El lenguaje de programación Java es conocido desde hace mucho tiempo como un “lenguaje del sector”. Se creó en los primeros años de Internet, pero la web se ha desarrollado muy rápidamente desde entonces. Además de la clásica arquitectura cliente-servidor, hay una serie de interesantes modelos alternativos: las aplicaciones basadas en contenedores, los microservicios, la computación sin servidor y las aplicaciones web reactivas se han establecido de forma generalizada. Estos tipos de aplicaciones han sido hasta ahora difíciles de implementar con Java. Gracias al entorno Quarkus, esto ha cambiado. El director de RedHat, Ken Johnson, lo explica así:

Cita

“… it's a very small Java stack, perfect for containers, serverless and other scenarios where you're running Java applications in the cloud.”

- Ken Johnson, Fuente: https://cloud.redhat.com/blog/quarkus-is-here-for-your-java

“[Quarkus] es una estructura Java muy pequeña, perfecta para contenedores, sin servidor y óptima para otros escenarios en los que se ejecutan aplicaciones Java en la nube.” (Traducción: IONOS)

Te presentaremos Quarkus y te mostraremos cómo este entorno está revolucionando la creación de aplicaciones Java.

¿Qué hace que Quarkus sea especial?

Quarkus es un entorno desarrollado por RedHat para crear aplicaciones Java. Quarkus se desarrolló con el objetivo de ejecutar programas Java en contenedores. En particular, se centra en el apoyo al software de configuración Kubernetes. Otro enfoque del desarrollo de Quarkus es el uso de bibliotecas y estándares Java establecidos.

“HotSpot”, del proyecto OpenJDK, se utiliza como máquina virtual Java (JVM) para que sea la capa de ejecución del código Java. Además, también se puede utilizar el desarrollo “GraalVM”, que se basa en HotSpot. Este último permite compilar el código Java en código máquina directamente ejecutable. Para entender el beneficio inmediato de utilizar Quarkus, veamos primero cómo se ejecutan las aplicaciones Java con y sin Quarkus.

¿Cómo se han ejecutado tradicionalmente las aplicaciones Java?

La idea básica que hizo que Java fuera algo revolucionario cuando apareció era tan simple como cautivadora: Java permitiría desarrollar un programa sin estar atado a un hardware o sistema operativo específico. Esta independencia de la plataforma se resume a menudo con la frase “escribe una vez, ejecuta en cualquier parte”. La portabilidad asociada permite trasladar el programa entre plataformas. ¡Qué gran truco! ¿Pero cómo funciona?

Como ocurre con otros lenguajes de programación, un programa Java comienza con un código fuente que puede ser leído por un humano. Para ejecutar las instrucciones del texto fuente en un ordenador, se generan las instrucciones correspondientes en el formato del procesador específico. Con Java, hay otro paso intermedio: el texto fuente se traduce primero a un formato intermedio, el llamado código de bytes, como ocurre con el lenguaje Python. A continuación, el código de bytes se ejecuta en la “Java virtual machine” (JVM). Para ejecutar un programa Java en un dispositivo, debe tener instalada una JVM.

El código de bytes se interpreta tradicionalmente para su ejecución en la JVM. Las instrucciones del código de bytes se traducen pieza a pieza en instrucciones de código máquina y se ejecutan. El proceso de compilación a tiempo real o “just-in-time compilation” (JIT) es más eficaz. Con ese proceso, el código de bytes también se convierte en código máquina, pero también entran en juego otras optimizaciones. En resumen, la ejecución de un programa Java implica los siguientes pasos:

  1. Compilar el código fuente de Java a código de bytes con el comando del compilador de Java ‘javac’:
javac java_program.java
  1. Ejecutar el código de bytes de Java con el comando de ejecución de Java ‘java’ - A continuación, se genera el código máquina:
java java_program
Nota

Aquí estamos hablando de una “máquina virtual”. Aunque el término es el mismo, en este caso no se refiere a ningún tipo de tecnología para virtualizar un sistema operativo. En cambio, el código intermedio se traduce a código máquina.

Por muy práctico que sea el modelo de Java “escribe una vez, ejecuta en cualquier parte”, el enfoque tiene algunos puntos débiles: El uso de la JVM conlleva una sobrecarga bastante importante. Por un lado, se requiere un cierto tiempo para iniciar la JVM, que se añade al tiempo de ejecución de la aplicación real. Por otro lado, además de un mayor consumo de memoria, hay una pérdida de rendimiento. Todo esto juega un papel menor en las aplicaciones que se ejecutan durante mucho tiempo. Sin embargo, el enfoque no es muy adecuado para las aplicaciones de corta duración, basadas en contenedores. Lo ideal es que estas se inicien lo antes posible. Un tiempo de inicio de varios segundos es inaceptable.

¿Cómo se ejecutan las aplicaciones Java con Quarkus?

A diferencia de la ejecución nativa de las aplicaciones Java, Quarkus ofrece varias ventajas. Vamos a diferenciar los dos modos que soporta Quarkus:

  1. Optimización del código de bytes y ejecución en la JVM
  2. Ejecución como código nativo tras la compilación

El código Java escrito con Quarkus puede ejecutarse normalmente en la JVM. Sin embargo, existen considerables ventajas en cuanto al consumo de memoria y al tiempo de inicio de una aplicación en ejecución. Para conseguirlo, Quarkus utiliza algunos trucos. En particular, una serie de pasos que consumen mucho tiempo se trasladan de la ejecución al proceso de construcción. Esto incluye los pasos que, de otro modo, se producen cada vez que se ejecuta una aplicación Java:

  • Carga y análisis de las configuraciones
  • Exploración de la ruta de acceso a las clases Java y resolución de las anotaciones
  • Creación de modelos de unidades para bases de datos o similares, si procede

Con Quarkus, estos pasos se realizan una vez y los resultados se almacenan en la caché para una rápida recuperación. Otra optimización del rendimiento consiste en que Quarkus reduce la cantidad de información dinámica disponible en tiempo de ejecución. Esta se sustituye por las correspondientes construcciones estáticas. Esto es especialmente útil en lo que respecta al uso en contenedores. Una aplicación en contenedor no suele cambiar nunca y siempre se ejecuta en el mismo entorno.

El segundo modo soportado por Quarkus para ejecutar aplicaciones Java es aún más interesante. Con la compilación por anticipado o “ahead-of-time compilation” (AOT), se genera un código máquina directamente ejecutable a partir del texto fuente de Java, en lugar del código de bytes, lo que significa que ya no es necesaria una JVM en el hardware de destino. El programa solo se ejecuta en una arquitectura de procesador específica y tiene que ser recompilado para otras plataformas. Sin embargo, esta restricción suele ser irrelevante para su uso en contenedores. El ahorro en el consumo de memoria y en el tiempo de inicio de la aplicación que se consigue con la compilación AOT es realmente impresionante. Compara las pruebas de rendimiento que hemos recogido de la página oficial de Quarkus:

Aplicación Escenario Uso de memoria Tiempo de la primera respuesta
Quarkus + AOT REST 12 MB 0.02 s
Quarkus + AOT REST + CRUD 28 MB 0.04 s
Quarkus + JIT REST 73 MB 0.94 s
Quarkus + JIT REST + CRUD 145 MB 2.03 s
Cloud Native Stack REST 136 MB 4.3 s
Cloud Native Stack REST + CRUD 209 MB 9.5 s
Nota

En cuanto a la terminología: REST significa que solo se ejecuta un servidor web en el contenedor. En el escenario REST + CRUD, se ejecuta una base de datos junto al servidor web. Para la pila nativa en la nube, el contenedor contiene una JVM, además de la aplicación Java.

¿Para qué se utiliza Quarkus?

Quarkus no es un entorno de aplicación más. Por el contrario, el software pretende redefinir lo que significa desarrollar aplicaciones con Java. Solo a modo de recordatorio: tradicionalmente, era más importante que una aplicación Java se ejecutara de forma estable durante mucho tiempo. El tiempo que tardaba la aplicación en iniciarse no era algo crítico.

Detente a considerar las aplicaciones basadas en contenedores: los nuevos contenedores pueden ser arrancados automáticamente por el software de configuración. La aplicación en el contenedor debe estar entonces lista para su uso inmediato. Además, a menudo se inician varios contenedores redundantes para un servicio. En consecuencia, la reducción del consumo de recursos conseguida con Quarkus se multiplica.

El director de RedHat, Alex Handy, lo resume así:

Cita

“When you think of serverless computing, microservices and the […] cloud, there's one language you're probably not [thinking of]: Java. And that's a real shame. […] Java was and is the workhorse language of business. It remains the third most popular language in the world […] It's been the language of choice for corporations that need to keep a single application up and running for years at a time. ”

- Alex Handy, fuente: https://thenewstack.io/quarkus-gives-spring-boot-users-a-path-to-serverless-and-live-coding/

“Cuando piensas en la programación sin servidores, los microservicios y la nube [...], hay un lenguaje en el que probablemente no estás pensando: Java. Y eso es una verdadera lástima. [...] Java ha sido y es el lenguaje de trabajo de las empresas. Sigue siendo el tercer lenguaje informático más popular del mundo [...] Ha sido el lenguaje elegido por las empresas que necesitan mantener una única aplicación en funcionamiento durante años.” (Traducción: IONOS)

Las ventajas de Quarkus son evidentes. Sin embargo, el entorno también tiene algunas limitaciones. Por ello, Quarkus no está pensado principalmente para migrar aplicaciones Java existentes. En cambio, merece la pena utilizar Quarkus como punto de partida para un nuevo desarrollo. A continuación, veremos algunas áreas de aplicación específicas. En todos los ejemplos mencionados, se utiliza Maven o Gradle como herramienta de compilación. El área de aplicación se determina configurando el comando ‘mvn’ o ‘gradle’. A continuación, la herramienta de compilación genera automáticamente las configuraciones y componentes necesarios.

Ejecución de aplicaciones de microservicios en Kubernetes con Java y Quarkus

Kubernetes es un software de configuración para aplicaciones de contenedores. El uso de Kubernetes con contenedores Docker es bastante común. Los servicios individuales de una aplicación se guardan como imágenes Docker y son gestionados por Kubernetes. El operador se encarga de la gestión de los contenedores generados a partir de las imágenes: Kubernetes inicia, controla y supervisa los servicios. A menudo, se inician varias copias de un servicio para compartir la carga y aumentar la tolerancia a fallos. Si uno de los servicios falla, el contenedor se destruye y se crea un nuevo contenedor a partir de la misma imagen. Java Quarkus incluye las configuraciones necesarias para su uso en Kubernetes.

Implementación de API REST y aplicaciones sin servidor con Java y Quarkus

REST es el tipo de arquitectura establecido desde hace tiempo para las aplicaciones web. Las API, en particular, se implementan en su mayoría siguiendo este enfoque. Una API REST se basa en una arquitectura cliente-servidor. La comunicación se realiza a través del protocolo HTTP utilizando los “verbos” GET, POST, PUT, DELETE. Estos corresponden a los conocidos “verbos” CRUD (“create, read, update, delete”) del entorno de las bases de datos. El intercambio de datos entre una API y un usuario suele realizarse mediante JSON.

La programación sin servidor es una arquitectura alternativa para las aplicaciones basadas en la nube. En este modelo, también conocido como “Function as a Service” (FaaS), una única función se ejecuta brevemente en un contenedor. La función es llamada, realiza un cálculo y después se desactiva de nuevo. A pesar del nombre, las funciones sin servidor siguen ejecutándose en los servidores. Los programadores ya no tienen que preocuparse por ellas. Con AWS Lambda, Google Cloud Functions y Microsoft Azure Functions, los entornos sin servidor están disponibles en las principales plataformas en la nube. El código Java puede utilizarse en estas plataformas con Quarkus.

Consejo

Crea tu propia REST API en un servidor dedicado de IONOS.

Construir aplicaciones web reactivas con Java y Quarkus

En contraste con la programación imperativa, la programación reactiva representa el paradigma de la programación moderna. El programador describe las acciones que deben tener lugar cuando se producen determinados eventos. Los representantes más conocidos de este estilo de programación son los entornos “React” y “Vue”, escritos en JavaScript. Ambos se centran en la creación de interfaces de usuario basadas en la web. Con Quarkus, se pueden implementar aplicaciones con un estilo imperativo y reactivo. Incluso es posible combinar ambos paradigmas.

¿Dónde se utiliza Quarkus?

Quarkus se diseñó con el objetivo de optimizar las aplicaciones Java para su uso en contenedores y entornos en la nube. Sin embargo, la posibilidad de compilar un programa Java directamente en código máquina abre posibilidades de aplicación aún más interesantes. Echemos un vistazo a las áreas de aplicación actuales más interesantes de Quarkus.

En primer lugar, recordemos cómo se ejecuta un programa Java desarrollado con Quarkus. Durante el proceso de construcción, el código fuente de Java se compila en código de bytes, que luego se traduce en código máquina cuando se ejecuta. Con Quarkus se puede generar código de bytes, que luego se ejecuta en un entorno de ejecución de Java, como la VM HotSpot, mediante interpretación o compilación just-in-time (JIT). Dependiendo de la configuración, entran en juego varias optimizaciones relevantes para el rendimiento.

Por otro lado, GraalVM, basado en HotSpot, puede utilizarse para generar una imagen nativa utilizando la compilación por anticipado (AOT). La imagen nativa es un archivo binario que contiene todas las bibliotecas y dependencias necesarias para ejecutar la aplicación. Como no se necesita una JVM para la ejecución, los mayores aumentos de rendimiento se obtienen con la compilación AOT.

Aplicaciones Java en entornos de contenedores

Kubernetes suele intervenir cuando se utiliza una aplicación Java en contenedores. Una aplicación Java empaquetada como imagen Docker también puede utilizarse en un clúster OpenShift. El uso de Quarkus con Kubernetes también puedes probarlo, por ejemplo, utilizando una instalación minikube en tu sistema local.

Funciones Java en entornos sin servidor

Utiliza Quarkus para implementar fácilmente una función escrita en Java en entornos sin servidor de Amazon, Google y Microsoft.

Programas Java en sistemas integrados

Con la posibilidad de crear una imagen nativa a partir de una aplicación Java, el código Java también puede utilizarse en sistemas integrados. Aquí entra en juego la compilación AOT, que garantiza un bajo consumo de memoria y tiempos de arranque rápidos para una aplicación concreta.

Quarkus comparado con otros entornos

Quarkus es adecuado para una amplia gama de escenarios de aplicación. Otros entornos son más específicos hasta cierto punto. Veamos un par de alternativas similares:

  • React: este entorno de JavaScript se ha establecido como el estándar de la programación reactiva del mismo nombre.
  • Open Liberty: este entorno de IBM también permite el desarrollo de aplicaciones de microservicios con Java. Al igual que Quarkus, Open Liberty viene con una funcionalidad de recarga en tiempo real.
  • Micronaut: con el entorno Micronaut, se pueden programar microservicios y aplicaciones sin servidor en Java. Al igual que con Quarkus, aquí se utiliza GraalVM.
  • Spring/Spring Boot: Spring es probablemente el entorno Java más popular para aplicaciones web. Spring se basa en GraalVM y, además de la creación de microservicios, soporta la programación reactiva y la recarga en tiempo real. En una comparación de rendimiento, Quarkus supera a Spring. Un proyecto existente de Spring puede migrar a Quarkus con relativa facilidad.

¿Cuáles son los pros y los contras de Quarkus?

La principal ventaja de desarrollar aplicaciones Java con Quarkus es la mejora del rendimiento. Esto es especialmente importante cuando se utilizan aplicaciones Java en entornos de contenedores. Las mejoras de rendimiento incluyen:

  • Tiempo de arranque rápido de la aplicación
  • Bajo consumo de memoria por parte de la aplicación en ejecución
  • Escalado casi inmediato de los servicios
  • Menor necesidad de espacio para las imágenes nativas

Además de las ventajas de rendimiento, Quarkus brilla especialmente por su facilidad de uso. Los desarrolladores experimentados de Java EE y Spring pueden aprender fácilmente a utilizar el entorno. También se benefician del hecho de que Quarkus se basa en un entorno sólido. Se utilizan las siguientes tecnologías estándar, entre otras:

  • Eclipse MicroProfile
  • Spring Dependency Injection
  • Hibernate ORM

Quarkus también ofrece un entorno de programación en vivo, en el que los desarrolladores pueden crear rápidamente un prototipo. La función de recarga en vivo contribuye a un desarrollo fluido: tras activar el modo dev, los cambios en el código fuente y la configuración se compilan en segundo plano. El desarrollador solo tiene que recargar la ventana del navegador para apreciar los cambios.

Por último, concluiremos con las desventajas de utilizar Quarkus. Estas se derivan principalmente de las optimizaciones que entran en juego durante la compilación.

  • En concreto, la reducción de la información dinámica generada durante el tiempo de ejecución puede provocar problemas en algunos escenarios.
  • Las posibilidades muy limitadas de inspección pueden dificultar la depuración de una aplicación.
  • El proceso de construcción altamente optimizado para las imágenes nativas lleva mucho tiempo.

Quarkus no está pensado para cualquier proyecto Java. Hasta cierto punto, el uso de este entorno requiere que los procesos se adapten.

¿Le ha resultado útil este artículo?
Page top