Este guia foi elaborado por Enéas Almeida com o principal objetivo de facilitar os repasses de informações à equipe.
RabbitMQ é um serviço de mensageria que utiliza o protocolo AMQP (Advanced Message Queuing Protocol) para transporte de dados. Esse protocolo nos permite trabalhar com envio de mensagens assíncronas.
- É um dos sistemas mais tradicionais de mensageria;
- Extremamente rápido e confiável;
- Implementa protocolos AMQP, MQTT, STOMP E HTTP, sendo o mais utilizado o AMQP;
- Desenvolvido em Erlang;
- Desacomplamento entre serviços;
- Por padrão, as mensagens são persistidas em memória;
- Padrão de mercado, muito utilizado e bastante testado.
Utilizando o protocolo TCP, o RabbitMQ abre apenas uma conexão e cria vários canais dentro dela. Isso porque, se cada canal criasse uma nova conexão, seria bastante custoso, pois, passaria sempre pelo processo de estabelecimento de conexão do TCP: Three-way Handshake.
Observação: Para cada canal aberto, abre uma thread.
Características | Kafka | RabbitMQ |
---|---|---|
Protocolos | O Kafka usa um protocolo binário via TCP. | Protocolo avançado de fila de mensagens (AMQP) com suporte via plug-ins: MQTT, STOMP. |
Arquitetura | Kafka é uma plataforma de streaming distribuída, projetada para lidar com grandes volumes de dados em tempo real. | RabbitMQ é um middleware de mensageria de propósito geral baseado em AMQP. |
Persistência | Kafka mantém os dados por um período configurável e permite que várias partes de um sistema leiam e gravem mensagens em tempo real. | Por padrão as mensagens são persistidas em memória. |
Casos de Uso | É adequado para casos de uso que exigem processamento de stream em tempo real, como pipelines de dados, análise de logs, processamento de eventos. | É ideal para aplicativos que exigem fila de mensagens tradicional, comunicação entre sistemas heterogêneos e integração de aplicativos. |
Atua como um roteador, ou seja, um ponto de entrada para as mensagens que são posteriormente encaminhadas para as filas específicas.
Utilizada quando existe uma alta demanda de processamento bloqueante como: processamento de uma fila de vídeos (que utiliza muito I.O), update em massa em uma carga de dados.
Utilizado em muitos cenários do nosso dia dia como: push notification, chat, envio de mensagens, principais tipos dessa categoria:
- Direct: Nesse tipo de implementação o roteamento de mensagens para filas é realizado com base em uma chave de roteamento. A mensagem é entregue à fila cuja chave de roteamento está exatamente correspondente à chave de roteamento da mensagem.
As mensagens são distribuidas entre os consumidores, utilizando o algoritimo de Round-Robin. |
Um vez a mensagem lida por algum consumidor, não é possível ser lida novamente por outro consumidor. |
🔑 No exemplo acima, foi alterada o binding key de x para y, dessa forma, as mensagens foram roteadas para outra fila.
- Topic: Similar à Direct Exchange, mas permite um casamento mais sofisticado entre a chave de roteamento e a chave de ligação da fila, usando padrões (wildcards) para rotear mensagens com base em um padrão definido.
No exemplo acima foi utilizado o wildcard checkout.log, com isso ele envia tanto para as filas *.log como checkout.log.
- Fanout: Envio de mensagens em massa, como um broadcast. Distribui todas as mensagens que recebe para todas as filas que estão vinculadas a exchange. Ignora a chave de roteamento da mensagem.
Esse tipo de implementação é utilizado na comunicação entre aplicações desenvolvidas em diferentes tecnologias. Exemplo: Um app desenvolvido em Node.js precisa fazer requisições em uma API Golang.
- FIFO: o RabbitMQ utiliza o FIFO como padrão, a primeira mensagem que entra, é a primeira mensagem que sai, entretanto, existe uma forma de configurar essa propriedade, porém, se torna algo mais complexo e se faz necesário ter alto domínio do caso de uso.
- Durable: Por padrão se utiliza filas duráveis, se a fila não for durável, ela vai ser removida assim que broker reiniciar;
- Auto-delete: Quando um consumidor desconecta da fila, automaticamente ela é removida.
- Expiry: Um tempo é definido para receber novas mensagens, caso não receba novas mensagens e/ou o consumidor não esteja conectado, a fila é removida;
- Message TTL: Diz a respeito do tempo de vida útil da mensagem, caso ela não seja consumida em um determinado período de tempo, é perdida e não poderá ser consumida;
- Overflow:
- Drop Head: Quando a fila entope de mensagens e chega uma nova, a mensagem mais antiga é removida para dar vez a nova que chegou;
- Reject Publish: Quando a fila entope, as novas mensagens vão sendo rejeitadas, dessa forma, fica claro, que existe uma opção para definir a quantidade máxima de mensagens por fila.
- Exclusive: Apenas o canal que criou a fila pode acessar;
- Max length/bytes: Define a quantidade máxima de mensagens ou bytes por fila e associa a essa opção o Drop Head ou Reject Publish;
- Algumas mensagens não são entregues, seja por problemas de redes ou outros motivos;
- São encaminhadas para o Exchange específica com uma fila associada, que encaminham as mensagens para uma Dead letter queue;
- As mensagens nesse estado, podem vir a serem consumidas para possíveis checagens, como se fosse um registro de log;
- As mensagens são armazenadas em disco e caso o broker reinicie, a mensagens não são perdaidas;
- Muito custosa, pois, exige muito I/O, esse recurso é utilizado geralmente quando são enviadas milhões de mensagens e os consumidores não dão conta de realizar as leituras de forma correta;
- Como garantir que as mensagens não serão perdidas no meio do caminho?
- Como garantir que as mensagens foram processadas corretamente pelos consumidores?
O RabbitMQ disponibiliza alguns recursos pensados em resolver as situações questionadas acima:
A exchange ao receber uma mensagem, confirma ao produtor que recebeu corretamente a mensagem.
O consumidor ao receber uma mensagem, retorna uma das 3 confirmações abaixo para fila:
Tipo | Como funciona |
---|---|
Basic.Ack | O consumidor recebe uma mensagem e processa o handler corretamente. Devolve um Ack para fila. |
Basic.Reject | O consumidor recebe uma mensagem porém não processa o handler. Devolve um Reject para fila. |
Basic.Nack | É exatamente como o Reject com uma excecção: processa várias mensagens ao mesmo tempo. |
As mensagens são persitidas em disco.
docker-compose up -d