Atualmente os sistemas tradicionais não conseguem suprir toda demanda de requisições de clientes. Muitas vezes é preciso investimento vertical, ou seja, aumentar a capacidade dos servidores a fim de aumentar a capacidade de processamento. Como soulção, podemos usar o O RabbitMQ DLX com Java Spring.
Por esse e outros motivos surgiram novas arquiteturas de software. O RabbiMQ é uma dessas soluções.
Sendo caracterizado por um sistema orientado a mensagem, com origem nos sistemas distribuídos, prove uma comunicação assíncrona baseada no protocolo AMQP.
Tutorial RabbitMQ:
Artigo 01: RabbitMQ #1 – O que são sistemas de mensageria?
Artigo 02: RabbitMQ #2 – RabbitMQ no docker-compose
Artigo 03: RabbitMQ DLX com Java Spring
No artigo RabbitMQ #1 – O que são sistemas de mensageria? exploramos alguns conceitos e descrevemos o RabbitMQ.
Caso já queira partir para prática, podes seguir o tutorial abaixo para configurar o RabbiMQ no docker com docker-compose.
Tutorial RabbiMQ e dockerer-compose
Obs: Vale lembrar que para configurar o docker-compose é preciso de permissão (de uma olhada em Permissão de grupo – docker-compose não funciona)
- RabbitMQ
- O que é uma Exchange?
- O que é uma Dead Letter Exchange?
- Vamos colocar a mão na massa…
- Conectando ao RabbiMQ
- Declarando Exchanges
- Definindo as propriedades da Exchange
- Criando o Binding entre a Exchange e Filas
- Código completo
- Artigos Relacionados
- Se quiser saber sobre outro protocolo de comunicação, o HTTP acesse:
RabbitMQ
Esse conceito de mensageira está fundamentado na matéria de sistemas distribuídos dentro da computação. Caracteriza-se por uma comunicação orientada a mensagem, onde podem ser classificadas como persistentes ou transientes.
Dessa forma, sistemas de mensageria (messaging systems) podem ser clusterizados, possuem escalabilidade, são tolerantes a falhas, com comunicação assíncrona. Além disso, é intuitivo dizer que opera como sistema distribuído.
Simplificando Redes – O que é um sistema de mensageria?
O que é uma Exchange?
Podemos compara uma exchange, no RabbiMQ, com um correio. Esse componente é responsável por receber, analisar e encaminhar as mensagens. Em outras palavras, uma Exchange é responsável pelo rotemaneto das mensagens.
Os parâmetros analisados, assim como o tipo de exchange influenciam o roteamento de uma determinada mensagem. O tipo mais simplista é o fanout. Essa categoria de exchange funciona em modo broadcast, ou seja, as mensagens que recebo serão encaminhadas para todas as filas conectadas a mim.
Existem outras categorias de exchanges dentro da arquitetura do RabbiMQ, são elas: direct, topic, head, default, e as dead letters exchanges.
O que é uma Dead Letter Exchange?
Dentro de um cenário de produção e consumo de mensagens, é possível dizer que haverão mensagens “perdidas” nas filas. Essas mensagens não foram recuperadas por nenhum consumidor por algum motivo.
Para estas mensagens temos um tratamento específico. Vamos pensar…. é justo dizer que se uma mensagem não foi recuperada ela pode ser direcionada para outro local. Este local pode ser uma exchange.
Dessa forma, as dead letter exchanges, como o próprio nome sugere, são exchanges receptoras de mensagens “esquecidas”. Elas por algum motivo não foram solicitadas, contudo, estão consumindo espaço nas filas e exchanges operantes.
Vamos colocar a mão na massa…
Nosso intuito agora consiste em criar uma aplicação de usuário que defina os parâmetros de uma DLX – Dead Letter eXchange.
Nossa linguagem de programação escolhida é o Java com Spring Boot framework. Contudo, o RabbitMQ é cross-language. Então, você pode escolher outra linguagem de programação de sua preferência, como Python.
Conectando ao RabbiMQ
O primeiro passo em qualquer aplicação consiste na conexão com o servidor/sistema. Neste caso, precisamos especificar alguns parâmetros como: IP, username, senha, e porta.
Obs: Verifique se a porta de sua máquina está aberta para realizar a conexão
No código abaixo criaremos uma factory do tipo ConnectionFactory definir os parâmetros de conexão. Após especificarmos o setHost, setUsername, setPassword e port devemos criar a conexão propriamente dita.
OK, criamos a conexão com o servidor. Agora o póximo passo estana criação do canal TCP a ser utilizado pelo produtor (aplicação que gera as mensagens).
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("172.24.0.2");
factory.setUsername("admin");
factory.setPassword("pass123");
factory.setPort(5672);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
Feito isso, podemos definir os parâmetros das exchanges. Agora, através deste canal criado podemos declara (caso ainda não exista) as exchanges e filas.
Livros Indicados:
E-Books de Redes e Segurança
Declarando Exchanges
Utilizamos então, o método exchangeDeclare da classe channel para declara asDLX e uma Exchange do tipo Topic. Os parâmetros destes métodos são: NOME, X_CATEGORIA.
Muito bem, declarmos nossas exchanges. Contudo, precisamos das filas para conectar os consumidores a elas. Sendo assim, declaramos a fila DLX_QUEUE para se conectar com a DLX_NAME.
//declarar as exchanges (main e dlx)
channel.exchangeDeclare(DLX_NAME,"topic");
channel.exchangeDeclare(EXCHANGE_NAME,"topic");
//declarar as filas: consumer, dlx
channel.queueDeclare(DLX_QUEUE,false,false,false,null);
Definindo as propriedades da Exchange
Muito bem, neste próximo trecho de código vamos definir os parâmetros utilizando um dicionário (MAP<String, Object>). Estaremos instânciando um dicionário dentro da variável map. A partir dela criaremos a configuração da DLX.
Os parâmetros são bem intuitivos na verdade. O primeiro deles etsá relacionado ao tempo de vida de uma mensage – TTL – Time To Live. Neste campo, estamos dizendo ao sistema que uma mensagem só poderá permanecer na fila por 10 segundos antes de ser direcionada a uma DLX.
Após definifa a condição precisamos definir o destino. bserve a terceira linha do código abaixo. Neste caso, a DLX DLX_NAME é o destino das mensagens que preencherem o requisito. Em outras palavars, excedam o TTL.
Próximo parâmetro…. agora iremos definir a label a ser utilizada. Uma label é uma identificação, é por ela que definimos para onde a mensagem vai. Logo, a routing-key será: DLX_BIDING_KEY. A routing key está associada a mensagem, enquanto a binding key está associada a fila.
Definimos todos os requisitos da DLX. Agora precisamos adicionar esses parâmetros a nossa configuração do sistema.
Criamos agora a fila CONSUMER_QUEUE, nela estamos enviando o nosso mapeamento map (dicionário) com todas informações da DLX. Abaixo estão descritas as propriedades de uma fila. Importante salientar que estas são do tipo boleano (true e false).
//parametros relacionados a fila: durável, exclusiva e auto-deletável channel.queueDeclare(queue, durable, exclusive, autoDelete, null);
O útimo parâmetro está reservado para argumentos relacionados a configuração do sistema. Justamente, neste ponto que enviamos o map como argumento do método.
Map<String, Object> map = new HashMap<String,Object>();
map.put("x-message-ttl",10000);
map.put("x-dead-letter-exchange",DLX_NAME);
map.put("x-dead-letter-routing-key",DLX_BINDING_KEY);
channel.queueDeclare(CONSUMER_QUEUE,false,false,false,map);
Criando o Binding entre a Exchange e Filas
Para que as exchanges e filas se conectem precisamos definir os binding. Todo biding possui um label (rótulo) associado, os biding keys. Juntamente com as routing keys, os bindig keys são utilizamos durante a fase de roteamento das mensagens.
Repare que toda a configuração foi realizada através do canal criado (channel.method). Agora não é diferente, iremos utilizar o queueBind para definir as conexões entre as filas e exchanges.
No primeiro binding defimos a ligação entre a DLX e sua respectiva fila. Na prática, dizemos ao RabbitMQ que toda mensagem que chegar com uma routing key compatível com a binding key da fila DLX será direcionada para DLX pelas exchanges de operação do sistema.
No segundo binding estamos associando a fila CONSUMER_QUEUE à exchange EXCHANGE_NAME com a label BINDING_KEY.
Obs: o operador .# está relacionado ao match entre a routing key e a binding key.
//bindingkey da dlx e consumer
channel.queueBind(DLX_QUEUE,DLX_NAME,DLX_BINDING_KEY+".#");
channel.queueBind(CONSUMER_QUEUE,EXCHANGE_NAME,CONSUMER_BINDING_KEY+".#");
connection.close();
Por fim, fechamos a conexão.
connection.close()
Código completo
Aqui você tem o código completo do passo a passo anterior. Neste tutorial, codamos uma aplicação em Java para definir os parâmetros das exchanges do RabbitMQ. Em posts futuros iremos criar o produtor e consumidor. Assim podemos análisar ocomportamento do sistema.
package DLX;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;
public class DlxConfig {
//DLX
private static final String DLX_NAME = "dlxExchange";
private static final String DLX_QUEUE = "dlxQueue";
private static final String DLX_BINDING_KEY= "dlxrk";
//EXCHANGE do sistema
private static final String EXCHANGE_NAME = "mainExchange";
//CONSUMER
private static final String CONSUMER_QUEUE = "queueConsumer";
private static final String CONSUMER_BINDING_KEY = "bkConsumer";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("172.24.0.2");
factory.setUsername("admin");
factory.setPassword("pass123");
factory.setPort(5672);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//declarar as exchanges (main e dlx)
channel.exchangeDeclare(DLX_NAME,"topic");
channel.exchangeDeclare(EXCHANGE_NAME,"topic");
//declarar as filas: consumer, dlx
channel.queueDeclare(DLX_QUEUE,false,false,false,null);
Map<String, Object> map = new HashMap<String,Object>();
map.put("x-message-ttl",10000);
map.put("x-dead-letter-exchange",DLX_NAME);
map.put("x-dead-letter-routing-key",DLX_BINDING_KEY);
channel.queueDeclare(CONSUMER_QUEUE,false,false,false,map);
//bindingkey da dlx e consumer
channel.queueBind(DLX_QUEUE,DLX_NAME,DLX_BINDING_KEY+".#");
channel.queueBind(CONSUMER_QUEUE,EXCHANGE_NAME,CONSUMER_BINDING_KEY+".#");
connection.close();
}
}
Tutorial RabbitMQ:
Artigo 01: RabbitMQ #1 – O que são sistemas de mensageria?
Artigo 02: RabbitMQ #2 – RabbitMQ no docker-compose
Artigo 03: RabbitMQ DLX com Java Spring
Quer saber mais sobre RabbitMQ?
Artigos Relacionados
- Docker Instalação
- Portainer: Instalação e Configuração
- Permissão grupo – docker compose não funciona
- RabbitMQ #1 – O que são sistemas de mensageria?
Se quiser saber sobre outro protocolo de comunicação, o HTTP acesse:
Aula teórica sobre o que é o RabbitMQ.
Como funciona na prática o RabbitMQ? Neste vídeo você poderá ver o comportamento do sistema através de aplicações do usuário em Java Spring boot.
Juliana Mascarenhas
Data Scientist and Master in Computer Modeling by LNCC.
Computer Engineer
Qual a melhor IDE para Python?
Encontrar a IDE perfeita é uma jornada pessoal que depende de vários fatores, como suas…