Presentamos el soporte de transmisión en RabbitMQ

¿Quiere saber más sobre el soporte de transmisión en RabbitMQ? Arnaud Cogoluègnes, ingeniero de personal de VMware, desglosa todo lo que hay que saber en la Cumbre RabbitMQ de 2021.

16 min read

¿Quiere saber más sobre el soporte de transmisión en RabbitMQ? Arnaud Cogoluègnes, ingeniero de personal de VMware, desglosa todo lo que hay que saber en la Cumbre RabbitMQ de 2021.

En julio de 2021, se introdujeron streams a RabbitMQ, utilizando un nuevo protocolo extremadamente rápido que se puede utilizar junto con AMQP 0.9.1. Los streams ofrecen una forma más fácil de resolver varios problemas en RabbitMQ, incluyendo grandes fan-outs, replay y time travel, y grandes logs, todo con un rendimiento muy alto (1 millón de mensajes por segundo en un clúster de 3 nodos). Arnaud Cogoluègnes, Ingeniero de Staff en VMware, presentó los streams y cómo se utilizan mejor.

Esta charla fue grabada en el RabbitMQ Summit 2021. La 4ta edición del RabbitMQ Summit se llevará a cabo como un evento híbrido, tanto en persona (en el lugar CodeNode en Londres) como virtual, el 16 de septiembre de 2022 y reunirá a algunas de las mayores empresas del mundo que utilizan RabbitMQ, todas en un solo lugar.

Streams: Un Nuevo Tipo de Estructura de Datos en RabbitMQ

Streams son una nueva estructura de datos en RabbitMQ que abren un mundo de posibilidades para nuevos casos de uso. Modelan un registro de solo agregado, lo que representa un gran cambio respecto a las colas tradicionales de RabbitMQ, ya que tienen semántica de consumidor no destructiva. Esto significa que cuando se leen mensajes de un Stream, no se eliminan, mientras que en las colas, cuando se lee un mensaje de una cola, se destruye. Este comportamiento reutilizable de RabbitMQ Streams se facilita mediante la estructura de registro de solo agregado.

Text from the image:(Streams: a un nuevo tipo de estructura de datos en RabbitMQ)
(Modela registros de solo anexar) (Persistente y replicado)(semántica de cliente no destructiva)(AMQP 0.9.1 y protocolo nuevo)

RabbitMQ también introdujo un nuevo protocolo, el protocolo Stream, que permite un flujo de mensajes mucho más rápido. Sin embargo, también puedes acceder a Streams a través del protocolo AMQP 0.9.1 tradicional, que sigue siendo el protocolo más utilizado en RabbitMQ. También son accesibles a través de otros protocolos que RabbitMQ soporta, como MQTT y STOMP.

Fortalezas de Streams

Los Streams tienen fortalezas únicas que les permiten destacar en algunos casos de uso. Estas incluyen: 

Difusión masiva

Cuando tienes varias aplicaciones en tu sistema que necesitan leer los mismos mensajes, tienes una arquitectura de difusión masiva. Los Streams son excelentes para las difusiones masivas, gracias a sus semánticas de consumo no destructivas, eliminando la necesidad de copiar el mensaje dentro de RabbitMQ tantas veces como haya consumidores.

Reproducción y viaje en el tiempo

Los Streams también ofrecen capacidades de reproducción y viaje en el tiempo. Los consumidores pueden adjuntarse en cualquier lugar de un Stream, utilizando un desplazamiento absoluto o una marca de tiempo, y pueden leer y volver a leer los mismos datos tantas veces como sea necesario.

Rendimiento

Gracias al nuevo protocolo de stream, los streams tienen el potencial de ser significativamente más rápidos que las colas tradicionales. Si necesitas un alto rendimiento o estás trabajando con mensajes grandes, los streams a menudo pueden ser una opción adecuada.

Mensajes grandes

Los Streams también son buenos para grandes registros. Los mensajes en los streams siempre son persistentes en el sistema de archivos, y los mensajes no permanecen en la memoria por mucho tiempo. Al consumirse, se utiliza la caché de archivos del sistema operativo para permitir un flujo de mensajes rápido.

RabbitMQ also introduced a new protocol, the Stream protocol, which allows much faster message flow, however, you can access Streams through the traditional AMQP 0.9.1 protocol as well, which remains the most used protocol in RabbitMQ. They are also accessible through the other protocols that RabbitMQ supports, such as MQTT and STOMP.  

Text from the image:(Grandes fan-outs) (Repetición/tiempo de viaje)(Alto rendimiento)(Grandes registros)

La Abstracción del Log

Un stream es inmutable, puedes añadir mensajes, pero una vez que un mensaje ha entrado en el stream, no se puede eliminar. Esto hace que la abstracción del log del stream sea una estructura de datos bastante simple en comparación con las colas donde los mensajes siempre se añaden y se eliminan. Esto nos lleva a otro concepto importante, el offset. El offset es simplemente un índice técnico de un mensaje dentro del stream, o una marca de tiempo. Los consumidores pueden indicar a RabbitMQ que empiece a leer desde un offset en lugar del principio del stream. Esto permite una fácil reproducción y viaje en el tiempo de los mensajes. Los consumidores también pueden delegar la responsabilidad de seguimiento del offset a RabbitMQ.

Text from the image:
(La abstracción de registros) 
(Un modelo de secuencias y un registro de solo anexar)

(Estructura de datos FIFO)
(Lectura no destructiva)

(Mensaje más viejo) (Compensar)(Último mensaje)(Proximo mensaje iría aquí en su lugar)

Podemos tener cualquier cantidad de consumidores en un stream, no compiten entre sí, una aplicación consumidora no robará mensajes de otras aplicaciones, y la misma aplicación puede leer el flujo de mensajes muchas veces.

Las colas pueden almacenar mensajes en memoria o en disco, pueden estar en un solo nodo o estar replicadas, los streams son persistentes y replicados en todo momento. Cuando creamos un stream, tendrá un líder ubicado en un nodo y réplicas en otros nodos. Las réplicas seguirán al líder y sincronizarán los datos. El líder es el único que puede crear operaciones de escritura y las réplicas solo se utilizarán para servir a los consumidores.

Colas de RabbitMQ vs. Streams

Los streams están aquí para complementar las colas y ampliar los casos de uso de RabbitMQ. Las colas tradicionales siguen siendo la mejor herramienta para los casos de uso más comunes en RabbitMQ, pero tienen sus limitaciones, hay momentos en los que no son la mejor opción.

Los streams son, al igual que las colas, una estructura de datos FIFO, es decir, el mensaje más antiguo publicado se leerá primero. Proporcionar un desplazamiento permite al cliente omitir el comienzo del flujo, pero los mensajes se leerán en el orden de publicación.

En RabbitMQ, tiene una cola tradicional con un par de mensajes y una aplicación consumidora. Después de registrar el consumidor, el intermediario comenzará a despachar mensajes al cliente y la aplicación puede comenzar a procesarlos.

Cuando, en este punto, el mensaje está en un punto importante de su vida útil, está presente en el lado del remitente y también en el lado del consumidor. El intermediario todavía necesita preocuparse por el mensaje porque puede ser rechazado y debe saber que aún no se ha reconocido. Después de que la aplicación termine de procesar el mensaje, puede reconocerlo y, a partir de este momento, el intermediario puede deshacerse del mensaje y considerarlo procesado. Esto es lo que podemos llamar consumo destructivo, y es el comportamiento de las colas clásicas y de cuórum. Al usar Streams, el mensaje permanece en el Stream mientras la política de retención lo permita.

Implementar configuraciones de gran difusión masiva con RabbitMQ no era óptimo antes de Streams. Cuando entra un mensaje, va a un intercambio y se enruta a una cola. Si desea que otra aplicación procese los mensajes, debe crear una nueva cola, vincular la cola al intercambio y comenzar a consumir. Este proceso crea una copia del mensaje para cada aplicación, y si necesita que otra aplicación procese los mismos mensajes, debe repetir el proceso; entonces otra cola, un nuevo enlace, un nuevo consumidor y una nueva copia del mensaje.

Este método funciona y se ha utilizado durante años, pero no escala de manera elegante cuando se tienen muchas aplicaciones consumidoras. Los streams proporcionan una mejor manera de implementar esto, ya que los mensajes pueden ser leídos por cada consumidor por separado, en orden, desde el Stream.

Rendimiento de los streams de RabbitMQ usando AMQP y el protocolo de Stream

Como se explica en la charla, hubo un mayor rendimiento con Streams en comparación con las colas de cuórum.

Obtuvieron alrededor de 40,000 mensajes por segundo con las Colas Quórum y 64,000 mensajes por segundo con Streams. Esto se debe a que Streams son una estructura de datos más simple que las Colas Quórum, ya que no tienen que lidiar con cosas complicadas como la confirmación de mensajes, mensajes rechazados o reencolado.

Text from the image: 
(Streams en AMQP)
(Cluster de 3 nodos (instancias c2-standard-16))
(Tarifas de publicación)
(mensajes/segundos)

(Colas Quorum)(Stream en AMQP)

Las colas de Quorum siguen siendo colas replicadas y persistentes de vanguardia, mientras que las Streams son para otros casos de uso. Al usar el protocolo Stream dedicado, se pueden lograr tasas de transferencia de un millón de mensajes por segundo.

Text from the image: (Protocolo Stream)
(Cluster de 3 nodos (instancias c2-standard-16))
(Tarifas de publicación)
(mensajes/segundos)
(Colas Quorum)
(Stream en AMQP)
(Stream con protocolo de stream)

El Protocolo Stream ha sido diseñado teniendo en cuenta el rendimiento y utiliza técnicas de bajo nivel como la API libC sendfile, la caché de página del sistema operativo y el agrupamiento, lo que lo hace más rápido que las colas AMQP.

El plugin RabbitMQ Stream y los clientes

Los Streams están disponibles a través de un nuevo plugin en la distribución principal. Cuando está activado, RabbitMQ comenzará a escuchar en un nuevo puerto que puede ser utilizado por los clientes que comprenden el Protocolo Stream. Está integrado con la infraestructura existente en RabbitMQ, como la interfaz de gestión, la API REST y Prometheus.

Text from the image: (Los Streams son también accesibles a través de un nuevo protocolo)
(Rápido) (Complemento en la distribución principal)(integración de gestión)

Hay un cliente dedicado en Java y Go que utiliza este nuevo protocolo de flujo. El cliente de Java es la implementación de referencia. También está disponible una herramienta de prueba de rendimiento. Los clientes para otros lenguajes también son desarrollados activamente por la comunidad y el equipo central.

El protocolo de flujo es un poco más simple que AMQP; no hay enrutamiento; simplemente se publica en un flujo, no hay intercambio involucrado, y se consume de un flujo como de una cola. No se necesita lógica para decidir dónde se debe dirigir el mensaje. Cuando publicas un mensaje desde tus aplicaciones cliente, este va a la red y casi directamente al almacenamiento.

Existe una excelente interoperabilidad entre los flujos y el resto de RabbitMQ. Los mensajes se pueden consumir desde una aplicación cliente AMQP 0.9.1 y también funciona en sentido contrario.

Ejemplo de caso de uso para interoperabilidad:

Las colas y los flujos viven en el mismo espacio de nombres en RabbitMQ, por lo que se puede especificar el nombre del flujo del que se desea consumir utilizando los clientes AMQP habituales y mediante el parámetro x-stream-offset para basicConsume.

Es muy fácil publicar con clientes AMQP porque es lo mismo que con las colas, se publica en un intercambio.

Text from the image: (Agregar Stream para Analiticas)
(Editor)(Cola) (Procesando AMER)
(Editor)(Cola) (Procesando EMEA)
(Editor)(Cola) (Procesando APAC)
             (Cola) (Analiticas globales)
((Posibilidad) editores multiprotocolos)

Arriba se muestra un ejemplo de cómo se puede imaginar el uso de streams. Se tiene un publicador que publica mensajes en un exchange y, según la clave de enrutamiento de los mensajes, se enrutan a diferentes colas. Por lo tanto, se tiene una cola para cada región del mundo. Por ejemplo, se tiene una cola para las Américas, una para Europa, una para Asia y una para la sede. Se tiene una aplicación consumidora dedicada que realizará un procesamiento específico para cada región.

Si se actualiza a RabbitMQ 3.9 o posterior, se puede simplemente crear un stream, vincularlo al exchange con un comodín para que todos los mensajes se enruten a las colas pero el stream reciba todos los mensajes. Luego se puede dirigir una aplicación que utiliza el Protocolo Stream a este stream y podemos imaginar que esta aplicación realizará análisis mundiales todos los días sin siquiera leer el stream muy rápido. Así es como podemos imaginar que los streams se ajustan a las aplicaciones existentes.

Garantías para RabbitMQ Streams

Los streams admiten entrega al menos una vez, ya que admiten un mecanismo similar a AMQP Publish Confirms. También hay un mecanismo de deduplicación, el agente filtra los mensajes duplicados según el número de secuencia de publicación, como una clave en una base de datos o un número de línea en un archivo.

Text from the image: (Garantías)                              (Mensajes de deduplicación)                (Control de flujo)
(Al menos uno)                        (publicando)
(Sin pérdida de mensajes)

En ambos lados, tenemos control de flujo, por lo que se bloquearán las conexiones TCP de los editores rápidos. El corredor solo enviará mensajes al cliente cuando esté listo para aceptarlos.

Resumen

Text from the image: (Streams: una nueva estructura de tipo de registro replicada y persistente en RabbitMQ)
(Desbloquear los nuevos escenarios con RabbitMQ)
(Grandes fan-outs) (Repetición/tiempo de viaje)(Alto rendimiento)(Grandes registros)

(Pruebalo)

Los Streams son una nueva estructura de datos replicada y persistente en RabbitMQ, que modelan un registro de solo anexión. Son buenos para distribución masiva, soportan funciones de reproducción y viaje en el tiempo, son adecuados para escenarios de alto rendimiento y para grandes registros. Almacenan sus datos en el sistema de archivos y nunca en memoria.

Si crees que los Streams o RabbitMQ podrían ser útiles para ti pero no sabes por dónde empezar, habla con nuestros expertos, siempre estamos dispuestos a ayudar. Si quieres ver las últimas características y estudios de casos del mundo de RabbitMQ, únete a nosotros en RabbitMQ Summit 2022.

Keep reading

Here’s Why You Should Build Scalable and Concurrent Applications with Elixir

In today's world, when dealing with high levels of system requests, you need applications that can handle them without slowing down. Here’s where Elixir comes in. Elixir is a programming language that is designed to create highly scalable and concurrent applications. Built on Erlang's virtual machine (BEAM), it has been used for decades to build highly reliable and scalable systems.

Here’s Why You Should Build Scalable Systems with Erlang

Building systems in the earlier days of the internet used to be pretty simple. While the system was admittedly pretty limited, the demand to scale past one or two servers

Creating a simple weather application with Phoenix LiveView

we will discuss our experience building an online weather application in Elixir using Phoenix LiveView. We created a real-time weather application that allows users to see the past, current, and forecast temperature and precipitation data for any UK postcode.