Processando Eventos de Rede Social usando EDA,Go, RabbitMQ e AT Protocol - Conhecendo o projeto - Lazuli Trending.

Processando Eventos de Rede Social usando EDA,Go, RabbitMQ e AT Protocol - Conhecendo o projeto - Lazuli Trending.

Buenas para você que está lendo este artigo, onde darei continuidade à série de artigos sobre RabbitMQ e Go. No artigo de hoje, vamos conhecer o nosso projeto, que será… rufem os tambores… a criação de uma aplicação que vai criar um Trending Topics do Bluesky, através de um fluxo de serviços para processar as informações em tempo real que chegam via Firehose do Bluesky (que é feito via WebSocket). Nos próximos artigos, para simplificar, será um monolito mesmo (ou, como uma piada interna que tenho com alguns amigos, será um monolito distribuído), mas com a lógica separada, simulando microsserviços, já que a ideia aqui é aprender sobre RabbitMQ, Go, AT Protocol e EDA, tudo bem? Então, vamos lá começar o artigo!

Conhecendo o desafio que será enfrentado

Bem, agora que sabemos o que será o projeto, vamos falar um pouco dele. Na verdade, essa nossa aplicação será uma versão simplificada inicialmente. Pois veja bem, para criar um Trending Topics mais preciso, seria necessário um estudo estatístico para a avaliação e pontuação das palavras que vamos receber. Eu acho até interessante esse ponto, mas confesso que estatística não é meu ponto forte. Quem sabe eu consiga uma participação especial em algum artigo aí na frente para melhorar nossa aplicação, hein?!

Agora que já falei o que é e que será uma versão simplificada (até tentei fazer algo mais elaborado durante a “pausa” de 2 semanas, quando fiz o artigo do pacote Lazuli, mas realmente ia precisar de mais tempo, então decidi simplificar), vamos conhecer um pouco o rascunho de como funcionará?

Imagem 1 - Rascunho das etapas do serviço

Em resumo, a aplicação vai ficar consumindo a Firehose do Bluesky via WebSocket. Esse consumidor vai, então, fazer um chaveamento para identificar que tipo de interação foi criada (se foi um post, like, reply, quote ou repost), para em seguida publicar em uma fila, onde essa mensagem publicada será consumida para validar algumas informações e calcular a pontuação das palavras presentes no texto. Com isso, a pontuação é salva, e então temos a lista de pontuação dos termos que mais se destacam no Bluesky, criando assim um Trending Topics simplificado.

Certo, mas se é simples assim, por quê usar EDA e RabbitMQ?

Olha, ótima pergunta! Mesmo sendo um desafio mais simples, usar EDA (Event-Driven Architecture) e RabbitMQ tem várias vantagens. Primeiro, ao usar EDA, a gente já se aproxima de um modelo onde cada parte do sistema reage a eventos de forma independente, o que ajuda muito a manter as coisas mais organizadas e flexíveis. Quer dizer, cada serviço pode fazer seu trabalho sem depender diretamente de outros, o que facilita bastante se a gente quiser trocar uma parte da lógica no futuro ou até adicionar novas funcionalidades sem precisar mexer em tudo. Assim, mesmo num monolito “disfarçado” de microserviços, dá para sentir o gostinho de como um sistema orientado a eventos funciona.

Lembra que mencionei que não sei bem estatística? Pois é, dessa forma, se eu quiser posteriormente trocar alguma parte do fluxo do monolito por um serviço especializado, é possível! Então vamos lá: tem todas essas vantagens, além de ser um bom estudo de caso para usar EDA aqui de maneira simplificada, sem precisar ainda trabalhar com padrões Saga, hein?!

Outro ponto que vale a pena mencionar é que, desta forma, a parte do código que vai ficar recebendo mensagens do WebSocket terá uma responsabilidade menor, fazendo com que, caso haja algum erro, o impacto seja menor. Além disso, o consumo de mensagens fica mais rápido e eficiente dessa maneira, já que o WebSocket concentra todo o fluxo de mensagens, o que resulta em diversos eventos em um único ponto focal. Esse primeiro ponto de contato separa esses eventos e os deixa mais explícitos para a aplicação.

E o RabbitMQ entra nessa história será o cara que organiza a comunicação entre os serviços. Ele age como uma espécie de “correio”, que recebe as mensagens de cada parte do sistema e entrega para quem precisa processar. Isso ajuda a gente a controlar o fluxo e a priorizar as mensagens, evitando que algum serviço fique sobrecarregado ou que a gente perca dados se um serviço cair temporariamente. Olha que eu já falei um pouco mais detalhado sobre o RabbitMQ no início dessa série, eim?! Se você chegou aqui, Em resumo, mesmo em algo simples, o uso do RabbitMQ e do EDA deixa o sistema mais robusto e pronto para crescer, caso a gente decida incrementar o projeto no futuro!

Imagem 2 - Rascunho de como ficará o serviço

Para que tantos consumidores e tantas filas?

Para entender a necessidade de tantos consumidores e tantas filas, é importante lembrar que cada fila representa um tipo específico de mensagem (post, like, reply, repost, quote), permitindo que cada categoria seja processada de forma independente e eficiente. Essa estrutura traz várias vantagens:

  1. Paralelismo no Processamento: Ao dividir o processamento em diferentes consumidores, conseguimos processar mensagens simultaneamente para cada categoria, sem criar gargalos. Isso é especialmente útil para eventos com maior volume, como likes ou reposts, que podem se acumular rapidamente. Com vários consumidores, garantimos que nenhuma fila fique sobrecarregada e o sistema mantenha um desempenho estável.
  2. Escalabilidade: Se o volume de um tipo específico de mensagem crescer, podemos aumentar a quantidade de consumidores apenas para aquela fila. Ou seja, se começarmos a receber muitos likes de uma vez, podemos alocar mais consumidores para a fila de likes sem mexer nas outras filas. Isso nos permite escalar o sistema de maneira mais flexível, sem precisar mudar a arquitetura geral.
  3. Isolamento de Falhas: Caso um consumidor de uma fila específica encontre algum problema ou falha, isso não interfere no processamento das outras categorias. Por exemplo, se uma lógica específica para posts estiver com um erro, os consumidores das outras filas continuam funcionando normalmente, evitando que a aplicação inteira pare.
  4. Facilidade no Tratamento de Erros e Retentativas: Com consumidores específicos para cada tipo de evento, conseguimos implementar lógicas de retentativa e tratamento de erros ajustadas para cada categoria. Assim, um erro em uma fila pode ser tratado de forma personalizada, como aplicando uma lógica de retentativa mais intensa para categorias críticas ou descartando eventos menos prioritários de forma mais rápida.
  5. Manutenção e Evolução Simplificadas: Ao segmentar o processamento, facilitamos futuras manutenções e expansões. Se decidirmos implementar uma análise de linguagem natural mais avançada só para os posts, por exemplo, podemos alterar a lógica do consumidor específico dos posts sem impacto direto nos outros tipos de mensagem.

Essa arquitetura com múltiplas filas e consumidores dá à aplicação uma base mais robusta e adaptável, pronta para lidar com o crescimento no volume de dados e com possíveis mudanças de escopo no futuro. Em resumo, mesmo que o desafio inicial seja mais simples, estruturar o sistema dessa forma traz flexibilidade e resiliência, essenciais em um contexto de processamento de dados em tempo real como o do Bluesky.

Mas isso é mesmo Event Driven Architecture?

Claro que sim! Pois para além das vantagens operacionais que comentei acima, essa organização em múltiplas filas e consumidores se alinha bem aos princípios da Arquitetura Orientada a Eventos (Event-Driven Architecture, ou EDA). A EDA é baseada na ideia de que eventos (como mensagens do WebSocket no nosso caso) disparam ações específicas e independentes no sistema, permitindo que cada evento seja tratado separadamente e que as respostas sejam realizadas em tempo real. Vamos ver como isso complementa nossa estrutura:

  1. Desacoplamento de Componentes: A EDA preza pelo desacoplamento dos componentes, o que permite que cada parte do sistema funcione de forma independente e reaja aos eventos que lhe dizem respeito. No caso, temos consumidores específicos para cada tipo de mensagem (posts, likes, replies etc.) que atuam apenas sobre eventos que caem em suas filas. Isso torna o sistema mais modular e facilita a manutenção e a escalabilidade, já que cada componente pode ser atualizado ou escalado individualmente.
  2. Eficiência na Resposta a Eventos: A EDA permite que nossa aplicação reaja a eventos do Bluesky em tempo real, sem bloquear o processamento de outros eventos. Com isso, mesmo que uma mensagem de post exija processamento mais complexo ou demore mais tempo, os consumidores de outras filas (como likes ou reposts) continuam processando suas mensagens normalmente. Essa abordagem distribui o trabalho de forma mais eficiente e permite que o sistema se adapte a diferentes volumes e tipos de eventos de maneira ágil.
  3. Escalabilidade Granular: A arquitetura orientada a eventos é ideal para sistemas que precisam escalar de forma granular, ajustando cada parte do processamento de acordo com o volume e a prioridade dos eventos. Como mencionamos antes, se o volume de likes aumentar, é possível aumentar a quantidade de consumidores especificamente para a fila de likes. Essa flexibilidade permite que o sistema cresça conforme a demanda, mantendo a eficiência sem comprometer a arquitetura geral.
  4. Capacidade para Adaptações Futuras: A EDA facilita a incorporação de novas funcionalidades e a substituição de partes do sistema sem grandes impactos na arquitetura. Por exemplo, se quisermos adicionar uma análise mais detalhada para determinados tipos de evento, como aplicar processamento de linguagem natural para os posts, podemos introduzir novos consumidores especializados ou até substituir a lógica existente sem afetar o resto do fluxo. Com essa abordagem orientada a eventos, temos uma arquitetura preparada para evoluir e integrar novas tecnologias ou funcionalidades à medida que o projeto cresce.
  5. Resiliência e Recuperação de Erros: Na EDA, cada evento é processado de forma independente, e erros podem ser gerenciados e recuperados de maneira localizada, sem comprometer o fluxo geral. No nosso caso, se algum problema ocorrer em um consumidor específico, as outras filas e consumidores continuam operando normalmente. Isso torna o sistema mais robusto e garante que falhas em um ponto específico não interrompam o processamento global.

Essas vantagens são especialmente valiosas em aplicações de alta frequência de eventos, como é o caso aqui com o Bluesky. Ao aplicar a Event-Driven Architecture com RabbitMQ, estamos criando um sistema que, mesmo em um contexto inicial simples, já possui estrutura para lidar com escala, flexibilidade e mudanças futuras, alinhando o desafio técnico ao potencial de crescimento do projeto.

E agora, vamos por a mão no código?

Bem, hoje não teremos código! Este artigo foi mais uma apresentação da aplicação, com alguns rascunhos do que vamos fazer. O código será apresentado em outro momento. Mas, diferente dos outros artigos, já vou deixar o link do repositório aqui para que, quem quiser, possa acompanhar o desenvolvimento da aplicação ao longo da semana e, quem sabe, já dar algum pitaco, hein?

Bom, é isso por agora, tá? Creio que estamos chegando ao final desta série, pois, com a aplicação apresentada, agora é desenvolvê-la. Acho que conseguiremos fechar em mais um ou dois artigos. Espero que tenha gostado, e te vejo no próximo artigo!