Fala Galera,

Hoje venho falar sobre como podemos desacoplar nossa aplicação, distribuindo o processamento de alguns serviços e ganhando escalabilidade. Esse paradigma em computação é conhecida como Computação Distribuída. Um dos conceito da computação distribuída é a troca de mensagem com a utilização de Filas. E neste post estarei demonstrando como usar uma topologia de fila com o RabbitMQ

O que é RabbitMQ Message Broker?

RabbitMQ é uma serviço de Message Broker, open source multiplataforma que foi desenvolvido em ERLANG, totalmente suportados por diversas linguagens de programação, fácil de usar, confiável, com administração nativa e failover.

Instalação

Para essa demostração, irei utilizar o Linux Ubuntu 14.04 LTS, nele estará instalado toda infraestrutura necessária

Vamos usar o APT-GET Repository para instalar o RabbitMQ, execute os comandos abaixos no terminal

Adicionar a entrada do RabbitMQ no source do ATP-GET

echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list

Adicionar a chave pública

wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -

Atualizar os pacotes

sudo apt-get update

Instalar o Message Broker

sudo apt-get install rabbitmq-server

Habilitando o Painel de Administração

Vamos habilita o seu painel de Administração assim ficará fácil de administrar os usuários, ver as filas e quantas mensagem cada fila tem.

Execute o comando abaixo para habilitar o Painel de Administração

rabbitmq-plugins enable rabbitmq_management

Com o comando executar, o painel de administração ficar acessível através da seguinte URL http://<servername>:15672. Para acessar o RabbitMQ cria um usuário para com o username guest e senha guest abaixo a imagem da página inicial do painel administrativo

rabbitmq

Dica: O usuário “guest” somente tem acesso ao painel de administração localmente caso esteja usando uma maquina virtual, crie um novo usuário através da aba Admin

Topologias

O RabbitMQ suporta diversas topologias que podemos usar para escalonar nosso processamos vou enumerar algumas suportadas

Topologia Simples – Consiste e um publisher e um consumer. Neste cenário o publisher envia uma mensagem para fila e o consumer recebe a mensagem da fila e realiza o processamento

simple

Topologia Worker- Consiste e um publisher e em um ou mais consumer. Neste cenário o publisher envia uma mensagem para fila e o RabbitMQ envia para o consumer que estiver disponível assim podemos escalar e colocar quantos consumer forem necessário. para realizar o processamento das mensagens. A fila do RabbitMQ é atômica ou seja, apenas um item da fila é obtido por vez, não há riscos de mais de um consumer obter a mesma mensagem.

worker

Publish/Subscriber: Consiste em fazer copia da mesma mensagem para uma ou mais filas que assinam esta mensagem e que contém um ou mais consumer. Para a copia de mensagem utilizaremos um fila chamada Exchange (fanout). 

publish

Aplicação de Exemplo em C#

Com o entendimento das topologias, vamos criar uma aplicação de exemplo que irá publicar uma mensagem na fila através do publisher e consumir esta mensagem através de um consumer

Vamos criar dois Console Applications, um será o responsável por enviar a mensagem para a fila e outra será o responsável por ler a mensagem da fila

Para utilizar os recursos da fila devemos instalar o pacote do RabbitMQ.Client através do NuGet Package. Execute o comando Install-Package RabbitMQ.Client  no Package Manager Console no Visual Studio

Publisher:

namespace Publisher
{
    class Program
    {
        static void Main(string[] args)
        {
            string hostName = "192.168.8.194";
            string userName = "sys";
            string password = "123456";
            string queueName = "Message-Queue";

            //Cria a conexão com o RabbitMq
            var factory = new ConnectionFactory()
            {
                HostName = hostName,
                UserName = userName,
                Password = password,
            };

            //Cria a conexão
            IConnection connection = factory.CreateConnection();

            //cria a canal de comunicação com a rabbit mq
            IModel channel = connection.CreateModel();

            //Cria a fila caso não exista
            channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);

            for (int i = 1; i &lt;= 500; i++)
            {
                String mensagem = $"Enviando a mensagem {i}";
                byte[] body = Encoding.Default.GetBytes(mensagem);

                //Seta a mensagem como persistente
                IBasicProperties properties = channel.CreateBasicProperties();
                properties.Persistent = true;

                //Envia a mensagem para fila
                channel.BasicPublish(exchange: String.Empty, routingKey: queueName, basicProperties: properties, body:body);
            }

            Console.WriteLine("Mensagem enviadas para fila");
            Console.Read();            
        }
    }
}

Ao executar o programa do publisher ele envia as mensagem para a fila conforme a imagem abaixo:

rabbitmq2

Consumer:

namespace Consumer
{
    class Program
    {
        static void Main(string[] args)
        {
            string hostName = "192.168.8.194";
            string userName = "sys";
            string password = "123456";
            string queueName = "Message-Queue";

            const int NUMBER_OF_WORKROLES = 3;

            //Cria a conexão com o RabbitMq
            var factory = new ConnectionFactory()
            {
                HostName = hostName,
                UserName = userName,
                Password = password,
            };

            //Cria a conexão
            IConnection connection = factory.CreateConnection();

            //cria a canal de comunicação com a rabbit mq
            IModel channel = connection.CreateModel();

            for (int i = 0; i &lt; NUMBER_OF_WORKROLES; i++)
            {
                Task.Factory.StartNew(() =&gt;
                {
                    lock (channel)
                    {

                        var consumer = new EventingBasicConsumer(channel);
                        consumer.ConsumerTag = Guid.NewGuid().ToString(); // Tag de identificação do consumidor no RabbitMQ
                        consumer.Received += (sender, ea) =&gt;
                        {
                            var body = ea.Body;
                            var brokerMessage = Encoding.Default.GetString(ea.Body);

                            Console.WriteLine($"Mensagem recebida com o valor: {brokerMessage}");
                            
                            //Diz ao RabbitMQ que a mensagem foi lida com sucesso pelo consumidor
                            channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: true);
                        };

                        //Registra os consumidor no RabbitMQ
                        channel.BasicConsume(queueName, noAck: false, consumer: consumer);

                    }
                });
            }

            Console.Read();
        }
    }
}

Ao executar o programa consumer conseguiremos ler as mensagens da fila conforme figura abaixo:

rabbitmq3

O RabbitMQ é um produto muito poderoso e flexível. Neste post vimos algumas características de funcionamento porém existem outras características que o torna ele uma produto fantástico. Com o RabbitMQ podemos desacoplar fluxos de programação garantindo assim escalabilidade e performance. 

Para saber mais sobre o RabbitMQ clique aqui

O código deste post pode ser encontrado no meu GitHub através deste link

Abs e até a próxima

Rafael Cruz

É desenvolvedor .NET há mais de 12 anos, certificado Microsoft desde de 2006, instrutor oficial Microsoft há 5 anos, Pós Graduado em Engenharia de Software pela UFRJ, suas certificações são Microsoft Certified Trainer, Microsoft Certified Solution Developer (Web, Application Lifecycle Management), Microsoft Certified Professional Developer, Microsoft Certified Tecnology Specialist.
Atualmente trabalha como arquiteto de sistema, escreve artigos no .NET Coders e no seu blog rafaelcruz.azurewebsites.net para compartilhar experiências na área de desenvolvimento Web, Aplicativos Móveis e Cloud Solutions.

Twitter LinkedIn 

Comentários

comentarios