Los diferentes reactores extendidos
Introducción
Reactor es una biblioteca de programación reactiva que ofrece un enfoque basado en el flujo para la programación asíncrona. Se utiliza para crear aplicaciones reactivas en Java. A continuación, se detallan los distintos proyectos de Reactor.
-
Reactor solo (reactor-core): como su nombre indica, es el corazón de la biblioteca Reactor. Proporciona los principales tipos de datos reactivos, tales como Flux y Mono, así como las operaciones para transformarlos, filtrarlos y combinarlos. Se trata de la base sobre la cual se construyen los demás proyectos de Reactor.
-
Reactor Netty (reactor-netty): integración de Reactor con Netty, que es un framework de red escalable para Java. Reactor Netty proporciona una implementación reactiva para operaciones de comunicación en red, tales como llamadas HTTP, servidores TCP y clientes WebSocket. Permite una comunicación de red de alto rendimiento y asíncrona.
-
Reactor RabbitMQ (reactor-rabbitmq): biblioteca que proporciona integración reactiva con RabbitMQ, que es un sistema de mensajería orientado a mensajes. Reactor RabbitMQ permite publicar y consumir mensajes RabbitMQ utilizando objetos Flux y Mono, haciendo que las interacciones con RabbitMQ sean reactivas.
-
Reactor Kafka (reactor-kafka): proyecto que proporciona integración reactiva con Apache Kafka, una plataforma de streaming de datos distribuidos. Reactor...
Reactor Netty
Hemos visto que es posible programar con Netty, pero que es tedioso y hay mucho código boilerplate.
El término código boilerplate("« código repetitivo » o « código pastel » en español") hace referencia a partes de código que deben escribirse en varios lugares de un programa, a menudo de la misma forma o de forma muy similar. Estas partes de código no contribuyen directamente a la lógica de negocio de la aplicación, pero son necesarias para que funcione correctamente, como la inicialización de variables, el manejo de excepciones, la configuración, etc. El código boilerplate puede hacer que el código sea más largo, menos legible y más propenso a errores, porque los desarrolladores tienen que copiar y pegar o reescribir el mismo código varias veces. También puede resultar tedioso de mantener, ya que cualquier cambio debe aplicarse en varios lugares. Para superar este problema, algunos frameworks y bibliotecas ofrecen herramientas para generar automáticamente código boilerplate, lo que ahorra tiempo y reduce el riesgo de errores. Por ejemplo, utilizando anotaciones o generadores de código, podemos evitar escribir manualmente determinadas partes de código repetitivo. Esto permite a los desarrolladores concentrarse en la lógica de negocio de la aplicación y hacer...
Programación Netty con Spring
Reactor Netty es un framework para el desarrollo de aplicaciones de red asíncronas basadas en eventos. Proporciona funcionalidades de cliente y servidor para los protocolos TCP, HTTP y UDP, que son no bloqueantes y soportan la contrapresión. Este framework está construido sobre la sólida base del framework Netty.
Reactor Netty es el servidor por defecto utilizado por Spring WebFlux. Cuando se crea una aplicación WebFlux con Spring, el servidor Reactor Netty se configura automáticamente para gestionar solicitudes y las respuestas asíncronas mediante programación reactiva. También puede configurar otros servidores si lo desea. Sin embargo, como Reactor Netty es la opción por defecto, se recomienda aprovechar al máximo la reactividad en Spring WebFlux.
Podemos usar la librería Spring Reactor Netty para hacer programación en red en un estilo funcional, como hacíamos antes con un motor como Vert.x, antes de que Spring Reactor Netty estuviera disponible.
La contrapresión nos permite advertir al llamante de que nos está llamando con demasiada frecuencia, o bien impulsar un clúster elástico para que añada nodos dinámicamente.
Para nuestros ejemplos, utilizamos Java 17 LTS porque 21 es, en el momento de escribir esto, incompatible con Lombok. Reactor funciona con Java 8 y posteriores, pero nosotros utilizamos Spring...
Protocolo TCP
Reactor puede utilizarse para diseñar una aplicación TCP para:
-
Cree aplicaciones de comunicación en tiempo real, tales como servidores de chat, sistemas de mensajería instantánea o aplicaciones de streaming de datos en continuo.
-
Implementar microservicios con comunicación basada en el protocolo TCP. Esto permite que los distintos microservicios se comuniquen entre sí de forma eficiente y reactiva.
-
Exponer datos a través de un protocolo TCP. Esto puede ser útil cuando se necesita proporcionar acceso directo a los datos para los clientes u otros sistemas.
-
Integrar sistemas heterogéneos utilizando protocolos de comunicación estándar tales como TCP/IP. Esto permite conectar sistemas dispares y facilitar el intercambio de datos entre ellos.
-
Creación de juegos multijugador en línea en los que la comunicación en tiempo real es esencial. Esto permite a los jugadores conectarse e interactuar con el servidor del juego de forma ágil.
Reactor Netty proporciona una herramienta fácil de usar y configurar. Se trata de la clase TcpServer, que oculta la mayor parte de la funcionalidad de Netty necesaria para crear un servidor TCP, a la vez que añade una contrapresión Reactive Streams.
Vamos a empezar con un par cliente/servidor que utilizaremos para explicar el comportamiento y las posibles variantes con más detalle más adelante. Vamos a utilizar reactor-netty como parte de una aplicación Spring-boot.
El lanzador:
@SpringBootApplication
public class ReactorNettyServerApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ReactorNettyServerApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
}
}
El servidor:
@Slf4j
@Component
public class ServerSimple {
// Inyecta el valor del puerto del servidor desde application.properties
@Value("${server.port}")
private int PORT;
// Inyecta el valor de wiretap desde application.properties
@Value("${server.wiretap}") ...
Servidor HTTP
En general, la utilización del servidor HTTP de Spring Reactor Netty es limitado, puesto que ya disponemos de WebFlux para ello. El servidor HTTP Spring Reactor Netty suele reservarse para casos concretos, tales como los cercanos a Vert.x o en escenarios con múltiples puertos con fines de simulación (como mocks).
Una de las ventajas de utilizar Spring Reactor Netty para un servidor HTTP es la posibilidad de gestionar la contrapresión. Esto permite controlar mejor el flujo de datos entre el servidor y los clientes, evitando problemas de sobrecarga o congestión.
Sin embargo, es importante señalar que Spring ha creado un proyecto dedicado específicamente a satisfacer esta necesidad: Spring WebFlux. Spring WebFlux es la versión reactiva del Spring MVC tradicional y ofrece una solución completa para gestionar aplicaciones reactivas y servidores HTTP.
En la mayoría de los casos, se recomienda utilizar Spring WebFlux en lugar del servidor HTTP Spring Reactor Netty, ya que esto le permite beneficiarse de todas las funcionalidades y ventajas de un enfoque totalmente reactivo.
La utilización del servidor HTTP Spring Reactor Netty se limitará a casos muy concretos fuera del alcance de este libro, tales como escenarios que requieran HTTP 2.0 o una optimización específica para los Server-Sent Events. Para la mayoría de las aplicaciones reactivas, Spring WebFlux...
Servidor UDP
Reactor Netty también ofrece la opción de crear servidores UDP. El servidor UDP es muy similar al servidor TCP en términos de implementación y configuración. Sin embargo, existen diferencias fundamentales entre UDP (User Datagram Protocol) y TCP (Transmission Control Protocol).
UDP es un protocolo de comunicación de red que permite enviar datagramas de manera no fiable y sin conexión. A diferencia de TCP, que garantiza la entrega de paquetes en orden y gestiona las retransmisiones en caso de pérdida, UDP no ofrece mecanismos de garantía de entrega o retransmisión.
La ligereza y velocidad de UDP lo convierten en una opción atractiva para ciertas aplicaciones en las que la pérdida de unos pocos paquetes no es crítica, como las aplicaciones multimedia en streaming o los juegos online. Sin embargo, esta velocidad y ligereza pueden provocar la pérdida de datos en caso de congestión o interrupción de la red.
Aunque el servidor UDP de Reactor Netty ofrece una alternativa ligera y rápida para algunas aplicaciones específicas, es importante tener en cuenta las limitaciones de UDP en términos de entrega fiable de paquetes y ordenación de mensajes.
He aquí cinco casos de uso comunes para un servidor UDP con Spring Reactor Netty:
-
Servidor de juegos en tiempo real: un servidor UDP puede utilizarse para la comunicación en tiempo real entre los jugadores...
Conclusión sobre el Reactor Netty
En conclusión, Reactor Netty es una potente biblioteca que ofrece un enfoque reactivo para construir servidores y clientes de red de alto rendimiento. Gracias a su arquitectura basada en el modelo de programación reactiva, Reactor Netty permite gestionar eficazmente muchos clientes simultáneos manteniendo un uso óptimo de los recursos.
Las características que ofrece Reactor Netty, como la gestión de conexiones asíncronas, el soporte de diversos protocolos de red (TCP, UDP), la personalización detallada de los parámetros de red y la compatibilidad con herramientas de monitorización como Micrometer, lo convierten en una opción ideal para aplicaciones con requisitos exigentes de rendimiento y escalabilidad.
El uso de Reactor Netty es especialmente relevante en el contexto de la programación reactiva, donde la gestión del flujo de datos es primordial. Su perfecta integración con el framework Spring también permite aprovechar al máximo las capacidades reactivas del ecosistema Spring.
Sin embargo, es importante tener en cuenta que Reactor Netty puede ser más complejo de utilizar que algunas alternativas para casos de uso más sencillos. Por ello, su uso está especialmente recomendado para escenarios que requieran una gestión avanzada de las conexiones, un alto rendimiento y escalabilidad.
Reactor Netty...
Reactor Rabbit MQ
RabbitMQ es un sistema de mensajería de código abierto basado en el protocolo AMQP (Advanced Message Queuing Protocol), que facilita el intercambio de mensajes fiables y asíncronos entre diferentes aplicaciones o componentes de un sistema distribuido. Utiliza colas que permiten a los productores enviar mensajes y a los consumidores recuperarlos y procesarlos. RabbitMQ garantiza la entrega segura de mensajes y ofrece características como la persistencia de mensajes, el enrutamiento flexible, los modelos avanzados de mensajería, la extensibilidad mediante plugins, el alto rendimiento y mecanismos de gestión de lista de espera. Se utiliza ampliamente en arquitecturas distribuidas para la comunicación entre servicios, gestión de lista de espera de tareas, implementación de flujos de trabajo, etc., ofreciendo una solución fiable y escalable para sistemas que requieren comunicación asíncrona y entrega garantizada de mensajes.
1. Uso de la parte de servidor de RabbitMQ
a. Configuración del servidor
En la línea de comandos: https://www.rabbitmq.com/management-cli.html
Tenemos una parte servidor y una parte cliente. El servidor puede instalarse de forma independiente o ejecutarse en un contenedor como Docker.
Podemos utilizar Docker:
Para ejecutar RabbitMQ en un contenedor Docker, puede utilizar la imagen oficial de RabbitMQ disponible en Docker Hub.
docker run -it --rm --name mi_rabbitmq -p 5672:5672 -p
15672:15672 rabbitmq:3.12-management
-
La opción -d lanza el contenedor en modo separado (en segundo plano).
-
--name my_rabbitmq define el nombre del contenedor como "my_rabbitmq" (puede elegir un nombre diferente si lo desea).
-
-p 5672:5672 expone el puerto 5672 del contenedor (el puerto por defecto de RabbitMQ) al puerto 5672 de su máquina host, permitiendo que aplicaciones externas se conecten a RabbitMQ.
-
-p 15672:15672 expone el puerto contenedor 15672, que se utiliza para la interfaz de gestión web de RabbitMQ.
-
rabbitmq:3-management especifica la imagen Docker a usar, en este caso la imagen oficial de RabbitMQ con el plugin de gestión.
Después de ejecutar el comando, RabbitMQ se descargará de Docker Hub y se lanzará en un contenedor. Puede comprobar el estado del contenedor en ejecución con el comando docker ps.
Para acceder a la interfaz de gestión web de RabbitMQ, abra...
Reactor Kafka
1. Introducción
Kafka es una solución de mensajería distribuida altamente escalable y de alto rendimiento. Gracias a su baja latencia y a su capacidad para gestionar flujos de mensajes de alta velocidad, Kafka se ha convertido en un popular servicio de mensajería, así como en una potente plataforma para el tratamiento continuo de flujos de eventos en tiempo real.
Apache Kafka ofrece tres API principales para facilitar su utilización.
-
Producer API/Consumer API (API Productor/Consumidor): esta API permite a las aplicaciones publicar mensajes en temas (topics) de Kafka y consumir mensajes de estos temas. Los productores envían datos a los temas, mientras que los consumidores leen estos datos de los temas para procesarlos o almacenarlos.
-
Connect API (API de conexión): esta API permite extraer datos de los sistemas de almacenamiento de datos existentes y cargarlos en Kafka o, a la inversa, empujar datos de los sujetos de Kafka a otros sistemas de datos. Esto facilita la integración de Kafka con diferentes ecosistemas de datos.
-
Streams API (API streams): esta API permite transformar y analizar en tiempo real los flujos de eventos publicados en Kafka. Permite a los desarrolladores construir pipelines de procesamiento continuo de datos, realizando operaciones de transformación, filtrado, agregación y análisis de flujos de datos.
Apache Kafka ofrece, por tanto, un conjunto de API flexibles y potentes que permiten a los desarrolladores crear sistemas de mensajería, integración de datos y procesamiento en tiempo real, satisfaciendo las necesidades de una gran variedad de escenarios de aplicación.
2. API reactiva para Kafka
Reactor Kafka es una API reactiva diseñada específicamente para Kafka, basada en los principios de Reactor y en los de las APIs Kafka Producer/Consumer. Mediante el uso de APIs funcionales y a la contrapresión no bloqueante, la API Reactor Kafka permite a las aplicaciones basadas en Reactor interactuar con Kafka de forma reactiva. Esta integración reactiva permite a los desarrolladores utilizar Kafka como bus de mensajes o plataforma de streaming en sus aplicaciones reactivas. Gracias a una gestión eficaz de la contrapresión, Reactor Kafka permite gestionar de forma óptima los flujos de mensajes entrantes, evitando problemas de sobrecarga y bloqueo. En comparación...