Cómo combina Quarkus la programación imperativa y reactiva

Este año planeamos desarrollar seriamente temas de contenedores, Cloud-Native Java y Kubernetes . Una continuación lógica de estos temas será la historia sobre el marco Quarkus, ya considerado en Habré. El artículo de hoy se centra no tanto en el "dispositivo subatómico ultrarrápido de Java" como en las perspectivas que Quarkus aporta a Enterprise. (Por cierto, regístrese y vaya a nuestro seminario web " Este es el marco Java nativo de Quarkus - Kubernetes ", que se llevará a cabo el 27 de mayo. Le mostraremos cómo comenzar "desde cero" o transferir soluciones ya preparadas)



Java y JVM siguen siendo extremadamente populares, pero cuando se trabaja con tecnologías sin servidor y microservicios orientados a la nube, Java y otros lenguajes para JVM se usan cada vez menos, ya que ocupan demasiado espacio en la memoria y se cargan muy lentamente, lo que los hace inadecuados para utilizar con contenedores de corta duración. Afortunadamente, esta situación está empezando a cambiar gracias a Quarkus.

¡Java subatómico ultrarrápido ha alcanzado un nuevo nivel!


42 lanzamientos, 8 meses de trabajo comunitario y 177 desarrolladores increíbles: el resultado de todo fue el lanzamiento en noviembre de 2019 de Quarkus 1.0 , un lanzamiento que marca un hito importante en el desarrollo del proyecto y ofrece muchas características y capacidades interesantes (se puede encontrar más información sobre ellas en el anuncio ) .

Hoy diremos cómo Quarkus combina modelos de programación imperativos y reactivos basados ​​en un solo núcleo reactivo. Comenzaremos con una breve digresión en la historia, y luego veremos más de cerca a qué reacciona el núcleo dual de Quarkus y cómo los desarrolladores de Java pueden aprovecharlos.

Mikroservisy , arquitectura basada en eventos y sin servidor-funciones - todo esto hoy, como dicen, está en aumento. Recientemente, la creación de arquitecturas basadas en la nube se ha vuelto mucho más simple y asequible, pero persisten los problemas, especialmente para los desarrolladores de Java. Por ejemplo, en el caso de las funciones sin servidor y los microservicios, existe una necesidad urgente de reducir el tiempo de inicio, reducir el consumo de memoria y hacer que su desarrollo sea más conveniente y agradable. Java en los últimos años ha realizado varias mejoras, como la funcionalidad de ergonomía modificada para contenedores, etc. Sin embargo, lograr que Java funcione en el contenedor aún no es fácil. Por lo tanto, comenzaremos analizando algunas de las complejidades intrínsecas de Java, que son especialmente agudas cuando se desarrollan aplicaciones Java orientadas a contenedores.

Primero, pasemos a la historia.


Arroyos y contenedores


A partir de la versión 8u131, Java tiene contenedores más o menos compatibles debido a las mejoras en la funcionalidad ergonómica. En particular, la JVM ahora sabe en cuántos núcleos de procesador se ejecuta, y puede configurar correctamente grupos de subprocesos, generalmente conjuntos de bifurcación / unión. Por supuesto, esto es genial, pero digamos que tenemos una aplicación web tradicional que utiliza servlets HTTP y se ejecuta en Tomcat, Jetty, etc. Como resultado, esta aplicación le dará a cada solicitud una secuencia separada y le permitirá bloquear esta secuencia mientras espera operaciones de E / S, por ejemplo, al acceder a una base de datos, archivos u otros servicios. Es decir, el tamaño de dicha aplicación no depende del número de núcleos disponibles, sino del número de solicitudes simultáneas. Además, esto significa que las cuotas o límites en Kubernetes por el número de núcleos no serán particularmente útiles aquí,y el trato terminará en trote.

Quedando sin memoria


Las corrientes son memoria. Y las restricciones de memoria dentro del contenedor no son en absoluto una panacea. Simplemente comience a aumentar el número de aplicaciones y subprocesos, y tarde o temprano encontrará un aumento crítico en la frecuencia de conmutación y, como resultado, una degradación del rendimiento. Además, si la aplicación usa marcos de microservicios tradicionales o se conecta a la base de datos, o usa el almacenamiento en caché, o de alguna manera consume memoria adicional, absolutamente necesita una herramienta que le permita mirar dentro de la JVM y ver cómo administra la memoria, y no matar JVM en sí (por ejemplo, XX: + UseCGroupMemoryLimitForHeap). E incluso a pesar del hecho de que, comenzando con Java 9, la JVM ha aprendido a aceptar cgroups y adaptarse en consecuencia, hacer copias de seguridad y administrar la memoria sigue siendo un asunto bastante complicado.

Cuotas y límites


Java 11 introdujo soporte para cuotas de CPU (como PreferContainerQuotaForCPUCount). Kubernetes también ofrece soporte de límite y cuota. Sí, todo esto tiene sentido, pero si la aplicación nuevamente va más allá de la cuota asignada, nuevamente llegamos a la conclusión de que el tamaño, como es el caso de las aplicaciones Java tradicionales, está determinado por el número de núcleos y con la asignación de un hilo separado para cada solicitud, entonces Hay poco sentido en todo esto.
Además, si utiliza cuotas y límites o funciones de escalado horizontal (escalado) de la plataforma que subyace a Kubernetes, el problema tampoco se resuelve por sí solo. Simplemente gastamos más recursos en resolver el problema original o, como resultado, terminamos usando recursos. Y si es un sistema altamente cargado en una nube pública, pública, seguramente comenzaremos a usar más recursos de los que realmente necesita.

¿Y qué hacer con todo esto?


Si es de una manera simple, utilice bibliotecas y marcos de E / S asincrónicas y sin bloqueo como Netty, Vert.x o Akka. Son mucho más adecuados para trabajar en contenedores debido a su naturaleza reactiva. Gracias a las E / S sin bloqueo, el mismo hilo puede procesar varias solicitudes simultáneas a la vez. Mientras una solicitud espera los resultados de E / S, su subproceso de procesamiento se libera y se toma para otra solicitud. Y cuando los resultados de E / S finalmente llegan, el procesamiento de la primera solicitud continúa. Al alternar el procesamiento de solicitudes dentro de la misma secuencia, puede reducir el número total de subprocesos y el consumo de recursos para procesar solicitudes.

Con E / S sin bloqueo, el número de núcleos se convierte en un parámetro clave, ya que determina el número de subprocesos de E / S que pueden ejecutarse en paralelo. Cuando se usa correctamente, esto le permite distribuir efectivamente la carga entre los núcleos y hacer frente a cargas más altas con menos recursos.

¿Cómo, y eso es todo?


No, hay una cosa más. La programación reactiva ayuda a hacer un mejor uso de los recursos, pero también tiene un precio. En particular, el código deberá reescribirse de acuerdo con los principios de no bloqueo y evitar el bloqueo de flujos de entrada-salida. Y este es un modelo completamente diferente de desarrollo e implementación. Y aunque hay muchas bibliotecas útiles, esto sigue siendo un cambio fundamental en la forma habitual de pensar.

Primero, debe aprender a escribir código que se ejecute de forma asíncrona. Tan pronto como comience a usar E / S sin bloqueo, debe prescribir explícitamente lo que sucederá cuando reciba una respuesta a la solicitud. Solo bloquear y esperar fallará. A cambio, puede pasar devoluciones de llamada, usar programación reactiva o continuación. Pero eso no es todo: para usar E / S sin bloqueo, necesita servidores y clientes sin bloqueo, y preferiblemente en todas partes. En el caso de HTTP, todo es simple, pero también hay una base de datos, sistemas de archivos y mucho más.

Aunque la reactividad total de extremo a extremo brinda la máxima eficiencia, dicho cambio puede ser difícil de digerir en la práctica. Por lo tanto, la capacidad de combinar código reactivo e imperativo se convierte en una condición necesaria para:

  1. Usar recursos de manera efectiva en las áreas más cargadas del sistema de software;
  2. Use un código de estilo más simple en sus otras partes.

Introduciendo Quarkus


En realidad, esta es la esencia de Quarkus: combinar modelos reactivos e imperativos dentro de un entorno de tiempo de ejecución.

Quarkus se basa en Vert.x y Netty, además de los cuales se utilizan varios marcos reactivos y extensiones para ayudar al desarrollador. Quarkus está diseñado para construir no solo microservicios HTTP, sino también arquitecturas controladas por eventos. Debido a su naturaleza reactiva, funciona de manera muy eficiente con los sistemas de mensajería (Apache Kafka, AMQP, etc.).

El truco es cómo usar el mismo motor a reacción para el código imperativo y reactivo.



Quarkus lo hace brillantemente. La elección entre imperativo y reactivo es obvia: usar tanto el núcleo reactivo como el otro. Y lo que realmente ayuda es un código rápido que no bloquea y procesa casi todo lo que pasa a través del hilo del bucle de eventos (hilo del bucle de eventos, también conocido como hilo IO). Pero si tiene aplicaciones REST clásicas o del lado del cliente, Quarkus está listo para un modelo de programación imperativo. Por ejemplo, el soporte de HTTP en Quarkus se basa en el uso de un motor a reacción y sin bloqueo (Eclipse Vert.x y Netty). Todas las solicitudes HTTP recibidas por su aplicación pasan primero por el bucle de eventos (IO Thread) y luego se envían a la parte del código que administra las solicitudes.Dependiendo del destino, el código de control de solicitud se puede invocar dentro de un subproceso separado (el llamado subproceso de trabajo, utilizado en el caso de servlets y Jax-RS) o utilizar el flujo de entrada-salida original (ruta reactiva, ruta reactiva).



Los clientes sin bloqueo que trabajan en la parte superior del motor Vert.x se utilizan para conectores de sistemas de mensajería. Por lo tanto, puede enviar, recibir y procesar mensajes de manera eficiente desde sistemas de clase de middleware de mensajería.

El sitio Quarkus.io recopiló algunas buenas pautas para ayudarlo a comenzar con Quarkus:


Además, hemos preparado lecciones prácticas en línea para familiarizarse con varios aspectos de la programación reactiva, y solo un navegador es suficiente para completarlos, no se requiere IDE para esto y no se requiere una computadora. Encuentra estas lecciones aquí .

Recursos utiles




10 videos tutoriales de Quarkus para familiarizarse con el tema


Como Quarkus.io escribe en el sitio , Quarkus es una pila de Java orientada a Kubernetes , mejorada por GraalVM y OpenJDK HotSpot y compilada a partir de las mejores bibliotecas y estándares de Java.

Para ayudarlo a comprender el tema, hemos seleccionado 10 videos tutoriales que cubren varios aspectos de Quarkus y ejemplos de su uso:

1. Presentación de Quarkus: el marco Java de próxima generación para Kubernetes


Autores: Thomas Qvarnstrom y Jason Greene
El objetivo del proyecto Quarkus es crear una plataforma Java para Kubernetes y entornos sin servidor, así como combinar modelos de programación reactivos e imperativos en un solo tiempo de ejecución para que los desarrolladores podría variar de manera flexible el enfoque cuando se trabaja con una amplia gama de arquitecturas de aplicaciones distribuidas. Obtenga más información de la conferencia introductoria a continuación.



2. Quarkus: Java subatómico ultrarrápido


Autor: Burr Sutter Un
video tutorial de la conferencia en línea de DevNation Live demuestra cómo usar Quarkus para optimizar aplicaciones empresariales Java, API, microservicios y funciones sin servidor en Kubernetes / OpenShift, haciéndolos mucho más pequeños, más rápidos y más escalables.



3. Quarkus y GraalVM: aceleramos Hibernate a súper velocidades y exprimimos a tamaños subatómicos


Autor: Sanne Grinovero
De la presentación aprenderá cómo apareció Quarkus, cómo funciona y cómo puede hacer que bibliotecas complejas como Hibernate ORM sean compatibles con las imágenes nativas de GraalVM.



4. Aprender a desarrollar aplicaciones sin servidor.


Publicado por Marthen Luther
El siguiente video muestra cómo crear una aplicación Java simple usando Quarkus y desplegarla como una aplicación sin servidor en Knative.



5. Quarkus: código con gusto


Publicado por Edson Yanaga
Wideguide para crear su primer proyecto Quarkus para comprender por qué Quarkus se está ganando los corazones de los desarrolladores.



6. Java y contenedores: ¿cuál será su futuro común?


Publicado por Mark Little
Esta presentación presenta la historia de Java y explica por qué Quarkus es el futuro de Java.



7. Quarkus: Java subatómico ultrarrápido


Autor: Dimitris Andreadis Dimitris Andreadis
Una descripción general de los aclamados desarrolladores de Quarkus: simplicidad, velocidades ultrarrápidas, las mejores bibliotecas y estándares.



8. Quarkus y sistemas reactivos subatómicos


Publicado por Clement Escoffier
Mediante la integración con GraalVM, Quarkus proporciona una experiencia de desarrollo súper rápida y un tiempo de ejecución subatómico. El autor habla sobre el lado reactivo de Quarkus y cómo usarlo al crear aplicaciones reactivas y aplicaciones de transmisión.



9. Quarkus y desarrollo rápido de aplicaciones en Eclipse MicroProfile


Publicado por John Clingan Al
combinar Eclipse MicroProfile y Quarkus, los desarrolladores pueden crear aplicaciones de contenedores MicroProfile completamente funcionales que se ejecutan en unas pocas decenas de milisegundos. El video detalla cómo codificar la aplicación contenedor MicroProfile para su implementación en la plataforma Kubernetes.



10. Java, versión Turbo


Autor: Marcus Biel
El autor muestra cómo usar Quarkus para crear contenedores Java súper pequeños y súper rápidos que le permiten hacer un gran avance, especialmente en entornos sin servidor.


All Articles