Este año planeamos desarrollar en serio los temas de contenedores, y . La continuación lógica de estos temas será hablar del marco Quarkus, ya en Habré. El artículo de hoy se centra no tanto en la estructura de la «Java subatómica ultrarrápida», sino en las perspectivas que Quarkus aporta a la empresa.

Java y la JVM siguen siendo extremadamente populares, pero al trabajar con tecnologías sin servidor y microservicios orientados a la nube, Java y otros lenguajes para la JVM se utilizan cada vez menos, ya que ocupan demasiada memoria y se cargan demasiado lento, lo que los hace inadecuados para el uso con contenedores de corta duración. Afortunadamente, esta situación está comenzando a cambiar gracias a Quarkus.
¡La Java subatómica ultrarrápida ha alcanzado un nuevo nivel!
42 lanzamientos, 8 meses de trabajo de la comunidad y 177 desarrolladores increíbles – el resultado de todo esto fue el lanzamiento en noviembre de 2019 , un lanzamiento que marca un hito importante en el desarrollo del proyecto y ofrece un montón de funciones y capacidades geniales (puede leer más sobre ellas en ).
Hoy contaremos cómo Quarkus une los modelos de programación imperativa y reactiva basados en un núcleo reactivo único. Comenzaremos con una breve excursión a la historia y luego examinaremos en detalle en qué consiste el dualismo del núcleo reactivo de Quarkus y cómo -los desarrolladores pueden aprovechar estas ventajas.
, y -Las funciones son, hoy en día, lo que se llama un área en auge. Desde hace poco, la creación de arquitecturas orientadas a la nube se ha vuelto mucho más fácil y accesible, sin embargo, los problemas persisten, especialmente para los desarrolladores de Java. Por ejemplo, en el caso de funciones serverless y microservicios, existe una necesidad urgente de reducir el tiempo de arranque, disminuir el consumo de memoria y, en definitiva, hacer que su desarrollo sea más cómodo y placentero. En los últimos años, Java ha introducido varias mejoras, como funcionalidades de ergonomía mejoradas para contenedores, entre otras. Sin embargo, lograr un funcionamiento adecuado de Java en un contenedor sigue siendo complicado. Por lo tanto, comenzaremos examinando algunas de las complejidades internas de Java que se manifiestan con mayor intensidad al desarrollar aplicaciones Java orientadas a contenedores.
Comencemos por la historia.

Flujos y contenedores
A partir de la versión 8u131, Java ha comenzado a soportar contenedores de manera más o menos efectiva gracias a las mejoras en el funcionalismo de ergonomics. En particular, ahora la JVM sabe en cuántos núcleos de procesador se está ejecutando y puede ajustar las piscinas de hilos en consecuencia, generalmente las piscinas fork/join. Sin duda, esto es maravilloso, pero supongamos que tenemos una aplicación web tradicional que utiliza servlets HTTP y se ejecuta en Tomcat, Jetty, etc. Como resultado, esta aplicación asignará un hilo diferente para cada solicitud y permitirá que este hilo se bloquee mientras espera operaciones de entrada/salida, por ejemplo, al acceder a bases de datos, archivos u otros servicios. Es decir, el tamaño de tal aplicación no depende de la cantidad de núcleos disponibles, sino de la cantidad de solicitudes concurrentes. Además, esto significa que las cuotas o límites en Kubernetes en cuanto a la cantidad de núcleos no ayudarán mucho aquí, y eventualmente terminará en una limitación.
Agotamiento de memoria
Los hilos son memoria. Y las limitaciones de memoria dentro de los contenedores no son una panacea. Simplemente comience a aumentar la cantidad de aplicaciones y hilos, y tarde o temprano se encontrará con un crecimiento crítico en la frecuencia de conmutaciones y, como consecuencia, con una degradación del rendimiento. Además, si la aplicación utiliza marcos de microservicios tradicionales o se conecta a una base de datos, o utiliza caché, o consume memoria de alguna otra manera, necesita evidentemente una herramienta que le permita mirar dentro de la JVM y ver cómo gestiona la memoria, sin acabar con la propia JVM (por ejemplo, XX:+UseCGroupMemoryLimitForHeap). Y a pesar de que, a partir de Java 9, la JVM aprendió a reconocer los cgroups y adaptarse en consecuencia, la reserva y gestión de memoria siguen siendo tareas bastante complejas.
Cuotas y límites
Java 11 introdujo soporte para cuotas de CPU (como PreferContainerQuotaForCPUCount). Kubernetes también ofrece soporte para límites y cuotas. Sí, todo esto tiene sentido, pero si la aplicación nuevamente excede la cuota asignada, volvemos a la situación en la que el tamaño – como sucede con las aplicaciones Java tradicionales – está determinado por la cantidad de núcleos y asigna un hilo separado para cada solicitud, es decir, no sirve de mucho.
Además, si se utilizan cuotas y límites o funciones de escalado horizontal (scale-out) de la plataforma subyacente a Kubernetes, el problema no se resuelve por sí mismo. Simplemente gastamos más recursos en resolver el problema original o terminamos despilfarrando recursos. Y si se trata de un sistema altamente demandado en una nube pública accesible, es casi seguro que empezamos a usar más recursos de los que realmente necesitamos.
¿Y qué hacer con todo esto?
En términos simples, se deben utilizar bibliotecas y marcos de entrada/salida asíncronos y no bloqueantes como Netty, o Akka. Son mucho más adecuados para trabajar en contenedores debido a su naturaleza reactiva. Gracias a la entrada/salida no bloqueante, el mismo hilo puede manejar múltiples solicitudes simultáneamente. Mientras una solicitud está esperando los resultados de entrada/salida, el hilo que la procesa se libera y se ocupa de otra solicitud. Y cuando los resultados de entrada/salida finalmente llegan, la procesación de la primera solicitud continúa. Alternando el procesamiento de solicitudes en el mismo hilo, se puede reducir el número total de hilos y disminuir el consumo de recursos para procesar solicitudes.
Con la entrada/salida no bloqueante, el número de núcleos se convierte en un parámetro clave, ya que determina cuántos hilos de entrada/salida pueden ejecutarse en paralelo. Si se utiliza correctamente, esto permite distribuir de manera efectiva la carga entre los núcleos y manejar cargas más altas con menos recursos.
¿Así que eso es todo?
No, hay algo más. La programación reactiva ayuda a utilizar mejor los recursos, pero también tiene su costo. En particular, el código tendrá que reescribirse según los principios de no bloqueo y evitar la bloqueo de hilos de entrada/salida. Y esta es una modelo de desarrollo y ejecución completamente diferente. Y aunque hay muchas bibliotecas útiles, sigue siendo un cambio radical en la forma habitual de pensar.
Primero, necesitas aprender a escribir código que se ejecute de manera asíncrona. Una vez que comiences a utilizar la entrada y salida no bloqueante, debes especificar claramente qué debe suceder al recibir una respuesta a una solicitud. Ya no puedes simplemente bloquear y esperar. En su lugar, puedes pasar callbacks, utilizar programación reactiva o continuaciones. Pero eso no es todo: para utilizar la entrada y salida no bloqueante, necesitas servidores y clientes no bloqueantes, y preferiblemente en todas partes. En el caso de HTTP, todo es simple, pero también hay bases de datos, sistemas de archivos y mucho más.
Y aunque la reactividad total y continua ofrece la máxima eficiencia, puede ser difícil de digerir en la práctica. Por lo tanto, la capacidad de combinar código reactivo e imperativo se vuelve una condición necesaria para:
- Utilizar los recursos de manera eficiente en las áreas más cargadas del sistema de software;
- Usar un código más sencillo en estilo en las demás partes.
Presentamos Quarkus
De hecho, esa es la esencia de Quarkus: combinar los modelos reactivo e imperativo en un solo entorno de ejecución.
Quarkus se basa en Vert.x y Netty, sobre los cuales se utiliza toda una serie de frameworks y extensiones reactivas diseñadas para ayudar a los desarrolladores. Quarkus está destinado a construir no solo microservicios HTTP, sino también arquitecturas impulsadas por eventos. Gracias a su naturaleza reactiva, trabaja de manera muy eficiente con sistemas de mensajería (Apache Kafka, AMQP, etc.).
La clave está en cómo utilizar el mismo motor reactivo tanto para código imperativo como para código reactivo.

Quarkus lo maneja magistralmente. La elección entre imperativo y reactivo es obvia: usar el núcleo reactivo tanto para uno como para otro. Y lo que realmente ayuda es el código no bloqueante y rápido, que maneja casi todo lo que pasa por el hilo del ciclo de eventos (event-loop thread, también conocido como IO thread). Pero si tienes aplicaciones REST clásicas o aplicaciones del lado del cliente, Quarkus tiene lista una modelo de programación imperativa. Por ejemplo, el soporte HTTP en Quarkus se basa en el uso de un motor no bloqueante y reactivo (Eclipse Vert.x y Netty). Todas las solicitudes HTTP que recibe tu aplicación pasan primero por el ciclo de eventos (IO Thread) y luego se envían a la parte del código que gestiona las solicitudes. Dependiendo del destino, el código de control de solicitudes puede ser llamado en un hilo separado (el llamado worker thread, que se aplica a servlets y Jax-RS) o puede usar el hilo de entrada y salida original (ruta reactiva).

Para los conectores de sistemas de transmisión de mensajes se utilizan clientes no bloqueantes que funcionan sobre el motor Vert.x. Por lo tanto, puedes enviar, recibir y procesar mensajes de sistemas de mensajería middleware de manera efectiva.
se indica que: se han reunido varias buenas guías que te ayudarán a empezar a trabajar con Quarkus:
Además, hemos preparado lecciones prácticas en línea para familiarizarte con diversos aspectos de la programación reactiva, y para completarlas solo necesitas un navegador; no se requiere ninguna IDE y ni siquiera un ordenador es obligatorio. Puedes encontrar estas lecciones .
Recursos útiles
- El sitio del proyecto Quarkus es -
- El proyecto Quarkus en GitHub es -
- Twitter del proyecto Quarkus es -
- Chat del proyecto Quarkus es -
- Foros del proyecto Quarkus son - !forum/quarkus-dev
10 tutoriales en video sobre Quarkus para familiarizarse con el tema
Como dicen en el sitio , canales lógicos - una pila Java orientada, diseñada para GraalVM y OpenJDK HotSpot, y construida a partir de las mejores bibliotecas y estándares de Java.
Para ayudarte a entender el tema, hemos seleccionado 10 tutoriales en video que cubren diversos aspectos de Quarkus y ejemplos de su uso:
1. Presentando Quarkus: Un marco Java de nueva generación para Kubernetes
Autores: Thomas Qvarnstrom y Jason Greene
El objetivo del proyecto Quarkus es crear una plataforma Java para Kubernetes y entornos serverless, así como combinar los modelos de programación reactiva e imperativa dentro de un único entorno de ejecución, para que los desarrolladores puedan variar flexiblemente su enfoque al trabajar con una amplia gama de arquitecturas de aplicaciones distribuidas. Descubra más en la conferencia introductoria a continuación.

2. Quarkus: Java subatómica y ultrarrápida
Autor: Burr Sutter
El video tutorial del seminario DevNation Live muestra cómo usar Quarkus para optimizar aplicaciones Java empresariales, API, microservicios y funciones serverless en un entorno Kubernetes/OpenShift, haciéndolos mucho más pequeños, rápidos y escalables.

3. Quarkus y GraalVM: acelerando Hibernate a velocidades extremas y reduciéndolo a tamaños subatómicos
Autor: Sanne Grinovero
En esta presentación aprenderá cómo surgió Quarkus, cómo funciona y cómo permite hacer bibliotecas complejas, como Hibernate ORM, compatibles con las imágenes nativas de GraalVM.

4. Aprendiendo a desarrollar aplicaciones serverless
Autor: Marthen Luther
El video a continuación muestra cómo crear una simple aplicación Java utilizando Quarkus y desplegarla como una aplicación serverless en Knative.

5. Quarkus: programar con placer
Autor: Edson Yanaga
Guía en video para crear su primer proyecto Quarkus, que permite entender por qué Quarkus está conquistando los corazones de los desarrolladores.

6. Java y contenedores: ¿cómo será su futuro conjunto?
Autor: Mark Little
Esta presentación introduce la historia de Java y explica por qué Quarkus es el futuro de Java.

7. Quarkus: Java subatómica y ultrarrápida
Autor: Dimitris Andreadis
Resumen de las ventajas de Quarkus que han sido reconocidas por los desarrolladores: simplicidad, velocidades extremadamente altas, mejores bibliotecas y estándares.

8. Quarkus y sistemas reactivos subatómicos
Autor: Clement Escoffier
Gracias a la integración con GraalVM, Quarkus proporciona una experiencia de desarrollo ultrarrápida y un entorno de ejecución subatómico. El autor habla sobre el lado reactivo de Quarkus y cómo utilizarlo al crear aplicaciones reactivas y aplicaciones de transmisión de datos.

9. Quarkus y desarrollo ágil de aplicaciones en Eclipse MicroProfile
Autor: John Clingan
Combinando Eclipse MicroProfile y Quarkus, los desarrolladores pueden crear aplicaciones contenedoras MicroProfile completamente funcionales que se inician en cuestión de decenas de milisegundos. El video detalla cómo codificar una aplicación contenedora MicroProfile para su implementación en la plataforma Kubernetes.

10. Java, versión "Turbo"
Autor: Marcus Biel
El autor demuestra cómo utilizar Quarkus para crear contenedores Java extremadamente pequeños y rápidos, permitiendo un verdadero avance, especialmente en entornos sin servidor.

Fuente: habr.com
