En los sistemas distribuidos y los microservicios , los intermediarios de mensajes son esenciales. Permiten la comunicación asincrónica , desacoplan los servicios y mejoran la confiabilidad y la escalabilidad. La arquitectura moderna depende en gran medida de los intermediarios de mensajes, lo que los convierte en un componente clave en muchos patrones de diseño.
Kafka y RabbitMQ son dos de los agentes de mensajes más populares. Son conocidos por ser confiables, eficientes y adaptables, y por contar con una excelente documentación, soporte y comunidades.
RabbitMQ es una solución gratuita y de código abierto, con licencia dual Apache License 2.0 y Mozilla Public License 2. Te permite usarla y modificarla según sea necesario. Funciona como un agente de mensajes puro, compatible con múltiples protocolos y ofrece funciones adicionales.
Kafka, también de código abierto bajo la licencia Apache 2.0, es más que un simple agente de mensajes: es una plataforma de transmisión de eventos distribuidos. Ofrece funciones avanzadas, entre ellas Kafka Streams.
Al comparar RabbitMQ y Kafka, no hay una solución "mejor"; se trata de encontrar la que mejor se adapte a su arquitectura y sus objetivos.
Este artículo le explicará las características y funciones clave, y comparará directamente ambos. Su objetivo es ofrecer una comprensión integral de las diferencias entre Kafka y RabbitMQ, lo que le ayudará a tomar una decisión informada en función de su problema y sus requisitos específicos.
RabbitMQ admite varios protocolos como:
Por otro lado, Kafka utiliza su protocolo binario basado en TCP optimizado para un alto rendimiento y se apoya en una abstracción de "conjunto de mensajes". Esta abstracción permite que las solicitudes de red agrupen los mensajes, lo que reduce la sobrecarga de los viajes de ida y vuelta de la red al enviar lotes en lugar de mensajes individuales. El protocolo personalizado de Kafka permite flexibilidad en el desarrollo y la optimización para escenarios de alta carga.
Sin embargo, el protocolo personalizado también tiene desventajas. Aísla a Kafka de otros agentes de mensajes, lo que genera una falta de interoperabilidad. A diferencia de RabbitMQ, que es compatible con cualquier cliente AMQP, Kafka requiere el uso de clientes de Kafka. No obstante, debido a la popularidad de Kafka y a los esfuerzos de la comunidad, los clientes de Kafka están disponibles para muchos lenguajes de programación.
El enfoque de enrutamiento en RabbitMQ y Kafka difiere significativamente.
Los componentes principales del enrutamiento de RabbitMQ:
Antes de profundizar en los Exchanges, conviene aclarar dos conceptos más:
Existen cuatro tipos de Exchange:
*(asterisco) coincide exactamente con una palabra.
#(hash) coincide con cero o más palabras.
Por ejemplo, una cola vinculada con la clave de enrutamiento "apple.*.banana" recibiría mensajes con claves como "apple.orange.banana" o "apple.strawberry.banana" . Una cola vinculada con #.banana recibiría mensajes con claves como "apple.banana" o "apple.orange.banana".
El enrutamiento de Kafka es más sencillo. Los componentes principales son:
En comparación con RabbitMQ, las capacidades de enrutamiento de Kafka son limitadas. No está diseñado para el enrutamiento granular, sino para un alto rendimiento y escalabilidad.
Una cosa importante a tener en cuenta aquí:
En RabbitMQ, cuando un consumidor recibe un mensaje de una cola, lo "roba". Si se confirma correctamente, los demás consumidores no recibirán el mensaje. Los consumidores de Kafka se comportan de la misma manera si están en el mismo grupo de consumidores. El grupo de consumidores es una abstracción de Kafka que permite que varios consumidores lean el mismo tema de forma independiente, lo que garantiza que cada grupo de consumidores procese todos los mensajes del tema.
En RabbitMQ, la durabilidad y la persistencia son características distintas:
Durabilidad. Es una propiedad de las colas y los intercambios. Hay dos tipos de colas: duraderas y transitorias. Una cola (o intercambio) duradera almacena sus metadatos en el disco y puede sobrevivir a un reinicio del agente. Las colas transitorias no.
Persistencia. Una cola duradera no garantiza la durabilidad del mensaje. Para que sea duradera, debe configurar la persistencia. Cuando el publicador envía un mensaje, puede especificar la propiedad de persistencia. En este caso, un mensaje se almacenará en el almacenamiento de disco interno y estará disponible después de que se reinicie el agente.
Kafka almacena todo en un disco. A diferencia de RabbitMQ, que elimina los mensajes después de la confirmación del consumidor, Kafka conserva todos los mensajes hasta que alcanzan un límite de tiempo de vida (TTL) o de tamaño del disco. Permite que los mensajes sean reprocesados por un grupo de consumidores diferente o el mismo.
Tanto RabbitMQ como Kafka admiten la agrupación en clústeres, donde varios agentes trabajan juntos.
En RabbitMQ, la agrupación en clústeres mejora la disponibilidad y garantiza la seguridad de los datos. Si hablamos de rendimiento, el escalado vertical es una forma preferible de potenciar RabbitMQ. El escalado horizontal puede añadir una sobrecarga de sincronización significativa. Por lo general, es preferible tener un clúster de 3 agentes para garantizar la disponibilidad en caso de que falle uno de ellos.
RabbitMQ no admite la partición de colas de manera predeterminada, pero vale la pena mencionar que sí la tiene.
Kafka escala de manera eficiente. No solo proporciona disponibilidad y seguridad de los datos, sino que también mejora el rendimiento del procesamiento de datos. El concepto clave aquí es la partición. Cada tema tiene una cantidad configurable de particiones. Cada partición funciona de manera aislada de las demás y actúa como un almacenamiento y procesamiento de datos físicos. Puede replicar cada partición en todo el clúster, lo que garantiza la tolerancia a fallas. Los productores y consumidores trabajan solo con la partición principal (o primaria). Si el agente con esta partición deja de funcionar, el sistema elige una nueva partición primaria de las réplicas.
Elegir la cantidad correcta de particiones es crucial. Una gran cantidad de particiones ralentiza la recuperación del sistema en caso de falla de un nodo. Por el contrario, limita el rendimiento y el nivel de paralelismo del grupo de consumidores. Dentro de un grupo de consumidores, cada partición puede trabajar con un solo consumidor (que es efectivamente un hilo en su aplicación). Por lo tanto, tener tres particiones no tendría sentido si hubiera más de tres consumidores porque el resto estaría inactivo.
RabbitMQ garantiza el orden dentro de una única cola. Un consumidor procesará los mensajes en orden. Sin embargo, la situación cambia con varios consumidores. Si un consumidor falla, el sistema devuelve los mensajes no confirmados a la cola, pero es posible que el siguiente consumidor ya esté procesando el siguiente lote. Entonces, ¿cuáles son las opciones?
RabbitMQ y Kafka ofrecen garantías de entrega "al menos una vez", lo que significa que es posible que haya duplicados, pero los mensajes se procesarán completamente al menos una vez.
Kafka tiene más funciones de entrega:
Como se mencionó anteriormente, al renunciar a la flexibilidad de enrutamiento, Kafka ofrece características poderosas a cambio.
Kafka ofrece potentes bibliotecas de procesamiento de streaming:
Con Kafka Streams, puede realizar agregaciones de tiempo en su tema y enviar los resultados a otro tema o base de datos.
Imaginemos que tiene un tema con tipos de cambio entre diferentes pares de divisas y desea agregar datos de un gráfico de apertura-máximo-mínimo-cierre (también OHLC) dentro de períodos de tiempo (5 minutos, 30 minutos, 1 hora, etc.).
Una opción es almacenar los datos en una base de datos de series temporales, que es adecuada para dicho procesamiento. Sin embargo, no es necesario si se tiene Kafka. Mediante agregaciones simples de Kafka Stream, se pueden calcular datos OHLC sobre un tema de Kafka y colocar los resultados en cualquier base de datos para realizar consultas posteriores.
Kafka también permite representar los mensajes procesados como una tabla. Coloca los resultados de la agregación en una abstracción de tabla, a la que se puede acceder mediante KSQL. Este estado de tabla es duradero. Si un agente se reinicia, restablecerá el estado más reciente del tema correspondiente.
Como vemos, Kafka va más allá de la funcionalidad básica del agente de mensajes y se adentra en el territorio del procesamiento en tiempo real y los ETL.
Tanto Kafka como RabbitMQ son excelentes herramientas para escenarios de alto rendimiento y baja latencia. La elección depende de las particularidades del caso de uso, la arquitectura y los requisitos futuros. Por ejemplo, Kafka es ideal para el almacenamiento de eventos de transacciones a largo plazo, mientras que RabbitMQ se destaca en escenarios que requieren compatibilidad de protocolos y flexibilidad de enrutamiento. Cuando tanto RabbitMQ como Kafka sean adecuados, considere sus necesidades futuras.