Descomplicando a mensageria

Antes de mergulharmos no conceito de mensageria, é importante entender o contexto em que ela se insere. Nos dias de hoje, os sistemas de TI estão cada vez mais complexos e distribuídos. Com o advento da computação em nuvem e a popularização dos microsserviços, a necessidade de sistemas que possam se comunicar de forma eficiente e confiável tornou-se ainda mais premente. É nesse cenário que a mensageria ganha destaque como uma solução poderosa para a comunicação entre diferentes partes de um sistema.

De forma muito resumida, podemos considerar a seguinte definição para mensageria:

Mensageria é uma forma de comunicação entre sistemas, que consiste na troca de mensagens (eventos), gerenciadas por um “message broker”, ou seja, um servidor que guarda e gerencia essas mensagens.

Vamos explorar alguns cenários onde a mensageria poderia ser empregada.

Cenário 1

Imagine que você tenha um microsserviço com 2 APIs e você decide incluir algo para salvar logs. Você quer que ele salve de todas as requisições feitas em ambas as APIs, informações como: quem fez a requisição, o que pesquisou, o que retornou, data, etc.

Uma das possibilidades seria implementar um sistema de log diretamente no código de cada API. Isso significa que você precisaria escrever a funcionalidade de log dentro do código de cada serviço, garantindo que cada ação realizada pelas APIs seja registrada. O modelo ficaria basicamente esse:

No entanto, fazendo dessa forma você encontraria um trabalho adicional significativo. Primeiro, há o esforço de desenvolvimento e manutenção: cada vez que uma nova API for criada ou uma existente for modificada, você precisará garantir que o sistema de log esteja atualizado e funcionando corretamente em cada uma delas. Além disso, isso pode levar a uma redundância de código e à necessidade de garantir a consistência entre os diferentes serviços. Imagine se, no futuro, você decidir mudar a forma como os logs são armazenados ou o formato deles: você teria que atualizar cada serviço individualmente, o que é uma tarefa tediosa e propensa a erros.

Agora vamos analisar o esquema com mensageria:

Com a mensageria, simplificamos o processo de log ao configurar nas APIs apenas um método para publicação de mensagens em uma fila. Isso desacopla a responsabilidade de salvar os logs da lógica principal das APIs. Em seguida, um serviço dedicado, que pode ser uma nova API ou um aplicativo console, por exemplo, é configurado para consumir essa fila e salvar os eventos no banco de dados.

A princípio, pode parecer que ter um serviço de consumo adicional introduz complexidade. Contudo, esse arranjo oferece vantagens significativas:

  • Desacoplamento: Alterações no banco de dados ou na estrutura da tabela de eventos afetam apenas o serviço de consumo, não as APIs que publicam as mensagens.
  • Facilidade de expansão: Ao adicionar mais APIs ao microsserviço, a configuração necessária é apenas a publicação de mensagens na fila, que é uma tarefa muito mais simples do que configurar o acesso ao banco de dados.
  • Resiliência: Se o banco de dados estiver indisponível, as APIs não são afetadas diretamente, pois elas apenas publicam as mensagens. A API de eventos, quando disponível, consumirá as mensagens e realizará o salvamento. Isso garante que os processos sejam independentes e que as funcionalidades críticas das APIs não sejam interrompidas por problemas no banco de dados.

Esta arquitetura também melhora a escalabilidade e a manutenção do sistema como um todo. Em vez de cada API ser responsável pelo registro de eventos, elas delegam essa tarefa ao message broker, simplificando suas próprias operações e permitindo que lidem melhor com o aumento do volume de requisições.

Na imagem que utilizamos como referência, há alguns termos-chave no contexto da mensageria que são fundamentais para o entendimento dessa arquitetura. Vamos explicar cada um deles e como se aplicam ao nosso exemplo:

  • Publisher (Publicador): É o componente que envia mensagens. No nosso exemplo, as APIs 1 e 2 atuam como publishers quando chamam o método para publicar eventos na fila. Eles são responsáveis por criar e enviar mensagens para o message broker, mas não se preocupam com o que acontece com a mensagem depois que é enviada.
  • Consumer (Consumidor): O consumidor é o componente que recebe mensagens. No diagrama, a API de Eventos desempenha esse papel, ‘consumindo’ ou recebendo as mensagens da fila e processando-as, que neste caso significa salvar as informações no banco de dados.
  • Message Broker (Corretor de Mensagens): O message broker é o intermediário que gerencia o tráfego de mensagens entre publishers e consumers. Ele garante que as mensagens sejam entregues aos consumidores certos e pode fornecer funcionalidades como persistência de mensagens, roteamento, segurança, etc. Exemplos de message brokers populares incluem RabbitMQ, Apache Kafka, AWS SQS e Azure Service Bus.

AMQP (Advanced Message Queuing Protocol): É um protocolo aberto padrão para mensageria que define como as mensagens devem ser formatadas e transmitidas. O AMQP ajuda a garantir interoperabilidade entre sistemas de mensageria distintos, permitindo que diferentes tecnologias se comuniquem de maneira eficaz. Ele suporta várias funcionalidades, incluindo filas, tópicos e exchanges.

  • Filas: As filas são estruturas de dados que armazenam mensagens até que possam ser consumidas. Elas operam geralmente em um modelo FIFO (First In, First Out), onde a primeira mensagem enviada é a primeira a ser recebida. Em nossa imagem, a fila é o local onde as mensagens de eventos das APIs são armazenadas antes de serem consumidas pela API de Eventos.
  • Tópicos: Os tópicos são um meio de enviar mensagens para múltiplos consumers de uma só vez, geralmente baseados em um padrão de publicação/subscrição. Eles são úteis quando mensagens semelhantes podem ser de interesse para diferentes partes de um sistema.
  • Exchange: Em sistemas de mensageria mais avançados, como o RabbitMQ, uma exchange é responsável por receber mensagens dos publishers e roteá-las para as filas corretas, com base em regras ou atributos da mensagem, como chave de roteamento, tópicos ou cabeçalhos.

No nosso exemplo, o message broker seria configurado com filas para armazenar temporariamente as mensagens até que a API de Eventos esteja pronta para processá-las. Isso poderia ser feito usando o AMQP para garantir uma comunicação eficaz e confiável entre os diferentes serviços.

Cenário 2

Vamos imaginar um sistema de e-commerce onde, ao concluir um pedido, o sistema precisa realizar uma série de ações: verificar o estoque, processar o pagamento, atualizar o inventário e enviar uma confirmação de pedido ao cliente.

Na imagem, temos um fluxo de processamento de pedido que envolve três APIs distintas:

  • API Ecommerce: Esta é a interface principal com a qual o usuário interage para realizar pedidos. Quando um pedido é feito, a API Ecommerce executa uma série de chamadas síncronas (HTTP) para outras APIs.
  • API Estoque: Após receber o pedido, a API Ecommerce faz uma chamada síncrona para a API Estoque para verificar se os itens do pedido estão disponíveis. Se os itens estiverem disponíveis, a API Estoque atualiza o estoque para refletir a quantidade reservada para o pedido.
  • API Pagamentos: Paralelamente ou subsequentemente à atualização de estoque, a API Ecommerce envia informações para a API Pagamentos para processar o pagamento do pedido. Este é um passo crítico, pois o pedido só pode ser finalizado com sucesso se o pagamento for aprovado.

Esse modelo, nesse contexto de ecommerce tem uma série de desvantagens:

Dependência: Há uma forte dependência linear entre os serviços, onde cada passo precisa ser concluído antes de passar para o próximo. O último dos passos após todo esse processo, é enviar uma mensagem ao cliente informando que o pedido foi concluído e ele receberá atualizações, porém, até que tudo tenha sido verificado é possível que tenha corrido bastante tempo, ainda que no cenário positivo de que todos os serviços estejam funcionando corretamente.

Falha: Se a API Estoque ou a API Pagamentos estiverem lentas ou fora do ar, o processo inteiro é interrompido.

Escalabilidade: Em períodos de alta demanda, como uma promoção ou feriado de compras, o sistema pode ficar sobrecarregado, uma vez que todas as ações são realizadas em um modo síncrono e bloqueante.

Agora, utilizando a comunicação assíncrona, o processo ficaria assim:

Quando um pedido é feito, a aplicação web publica uma mensagem em uma fila do message broker e imediatamente retorna uma resposta ao usuário informando que o pedido foi recebido e está sendo processado.

Enquanto isso, serviços separados atuam como consumers das mensagens da fila:

Um serviço verifica o estoque e atualiza a fila com o status do inventário.

Outro serviço processa o pagamento e publica o resultado em uma nova fila ou atualiza o status da mensagem existente.

A aplicação web não depende do estado ou da disponibilidade imediata dos serviços de estoque, pagamento ou envio de confirmação. O usuário recebe um feedback rápido de que seu pedido está sendo processado, sem ter que esperar por todas as etapas subsequentes. Por fim, se um dos serviços estiver indisponível temporariamente, as mensagens ficarão na fila até que possam ser processadas. Isso evita a perda de pedidos e permite que os serviços sejam recuperados sem afetar a experiência do usuário.

Essa abordagem assíncrona com mensageria fornece uma arquitetura escalável, resiliente e eficiente, que pode lidar melhor com altos volumes de pedidos e com a complexidade dos processos de back-end.

Conclusão

Poderíamos passar um bom tempo discutindo as diversas vantagens que a mensageria oferece em variadas arquiteturas de sistemas. No entanto, com os dois exemplos apresentados, já podemos ter uma boa ideia de quando essa tecnologia se torna não apenas útil, mas essencial para a eficiência e escalabilidade de nossos projetos.

Como vimos, a mensageria traz desacoplamento, resiliência e uma melhor experiência para o usuário, qualidades indispensáveis em sistemas modernos e distribuídos. Existem diversos message brokers disponíveis, cada um com suas peculiaridades e casos de uso.

Nos próximos posts, estarei trazendo um exemplo prático utilizando o RabbitMQ, um dos message brokers mais populares, em um ambiente .NET. Mostraremos que, apesar de parecer intimidador no início, a configuração de um sistema de mensageria é bastante acessível e traz benefícios que superam de longe o esforço inicial para entendê-lo e implementá-lo.

Postar um comentário

0 Comentários