Quase todos os aplicativos hoje em dia, tem algum sistema de mensagens, olhe agora para o seu celular, qual as notificações que mais chamam sua atenção? Provavelmente será alguma coisa relacionada a mensageria. Porém, desenvolver uma aplicação com esse tipo de funcionalidade é uma tarefa complexa e precisa de certos cuidados para garantir que tudo funcione como deveria com o gasto correto de recursos e tecnologia.
Qualquer programador ou engenheiro de software quando está na faculdade ou em algum curso de desenvolvimento, vai passar pelo desafio de criar um sistema de mensagens. Mas normalmente a única exigência, é que tudo “funcione”, e geralmente o teste é feito de mensagens de “um para um”, sem se preocupar com quanto de recurso de servidor e rede estão sendo utilizados. Quando vamos para o “mundo real”, várias variáveis adicionais entram no radar, e nesse texto vamos explorar alguns desafios que encontrei, ao desenvolver a funcionalidade de mensagens do aplicativo BeautyConnect.
Requisitos e desafios:
A premissa era simples: os usuários cadastrados dentro da rede social do aplicativo BeautyConnect, precisam ter os meios para trocar mensagens, seja para conversarem, ou tirar dúvidas sobre produtos e serviços. A funcionalidade de mensagens não é o “core” da regra de negócio (já que os usuários não vão instalar o app apenas para isso), mas é um canal importante e com relevante impacto em toda a estrutura. A funcionalidade de mensagens deveria ter as seguintes premissas:
- Usuário A pode conversar com Usuário B livremente, não sendo necessário o “aceite” do destinatário para receber mensagens;
- As mensagens precisam ser enviadas e atualizadas em tempo real;
- O usuário precisa saber visualmente se tem mensagens não lidas;
- A troca de mensagens será apenas via texto, sem o envio de arquivos de mídia;
- O administrador geral da plataforma, precisa de alguma maneira acompanhar essas mensagens, sem precisar de algum meio “técnico” para isso. (Fins de moderação);
Baseado nas premissas acima, comecei a minha pesquisa sobre como seria a melhor abordagem tanto de construção, como de tecnologia para esse tipo de funcionalidade, observando também a questão de performance, já que pode ocorrer de centenas, milhares de usuários troquem mensagens simultaneamente, e o servidor precisa usar de maneira eficiente os recursos para processar essa demanda.
O sistema de mensagens do Facebook e do Whatsapp
A primeira coisa que pensei durante minhas pesquisas, era como será que os maiores aplicativos com mensageria do mercado funcionavam? Pensei logo no Whatsapp, e no Messenger do Facebook. Tive muito sucesso com as documentações do time de engenharia do Facebook, que mantem online vasta documentação sobre como os serviços deles funcionam. Como o documento Erlang at Facebook: A Facebook Chat Architecture, demonstrando como é a estrutura técnica da infra de mensagens do Facebook. Cheguei a achar alguma coisa do Whatsapp, mas muito abstrata, sem demonstrações reais de como eles optimizam recursos etc, provavelmente por causa da criptografia “ponto a ponto” que o Whatsapp aplica a suas mensagens, o que ninguém sabe muito bem como isso funciona direito na prática (apenas na teoria);
Vamos analisar alguns pontos:
- A troca de mensagens entre dois pontos, existe desde os primórdios da internet, já que quando ela surgiu, foi justamente para que o ponto A enviasse uma mensagem para o ponto B:
O problema é que nessa época, a preocupação era só “enviar e receber”, mas agora temos coisas como lidas ou não lidas, online e offline, centenas de mensagens por segundo etc. Então, de modo geral, hoje a troca de mensagens é feita em uma estrutura parecida com essa:Onde cada aplicação tem vários servidores, e com base na “carga” de cada um (o quanto de disponibilidade de recursos, como memória, banda etc) direcionamos ou recebemos as informações de cada usuário para a troca de “pacotes” (texto ou mídia); A prioridade é a troca de mensagens (o usuário A enviar e/ou receber a mensagem do usuário B), e depois salvar isso no banco de dados seja para backup ou para histórico:O salvar no banco de dados, varia de acordo com o paradigma de cada empresa, por exemplo, Skype da Microsoft, salva as mensagens em arquivos locais dentro do computador ou dispositivo do usuário, e salva esse “arquivo de histórico” na nuvem, sem salvar em um banco formato SQL. O Facebook faz algo parecido, deixando salvo no SQL apenas um log, já o Whatsapp salva todas as mensagens em um banco de dados. Para mim faz bastante sentido a estratégia do Skype e do Facebook, já que não tem por que salvar em um banco de dados relacional como o SQL dados que não tem qualquer relacionamento. Talvez por isso faça sentido tecnologias como o NodeJS+Express+MongoDB, que vão criar arquivos JSON padrão NoSQL para salvar esse tipo de informação.No caso do Whatsapp, eles ainda usam uma especie de “SQL Local” para que as mensagens fiquem salvas também no dispositivo do usuário. Deixar as mensagens salvas no dispositivo faz sentido, mas usando SQL? Poderia ser algo como o Skype ou MongoDB salvando em arquivos formato XML ou jSON que são bem mais rápidos, mas provavelmente, essa estratégia se de por causa da criptografia:Já o sistema do Facebook é bem mais simples em comparação do Whatsapp, salvando as mensagens em arquivos de texto, e criando registros no banco de dados apenas para fins de log. Um ponto interessante é que eles dão prioridade de tempo de servidor para os usuários que estejam online. Um usuário que envia uma mensagem para um outro usuário offline, poderá ter um tempo de execução maior (mais lento). O que faz bastante sentido, já que priorizar quem está online é uma boa estratégia de negócio e engajamento:
A primeira versão da funcionalidade de mensagens da BeautyConnect
Com a pesquisa feita, chegou a hora de colocar a mão na massa. A principio, para testar as funcionalidades de front-end, e termos um protótipo funcional, defini como tecnologia PHP+MySQL para salvar as mensagens, e toda a comunicação entre o usuário A e o usuário B ser feita via Ajax. Apesar de funcional, essas tecnologias acabam usando muitos recursos da infraestrutura, mas para um ambiente inicial, o fator tempo de desenvolvimento teve um peso maior:A estrutura montada ficou assim:Apesar de funcional, não é uma maneira inteligente de se aplicar esses recursos. Isso por que eu consulto o banco de dados de 2 em 2 segundos para consultar se existem novas mensagens. Duas pessoas, conversando por 5 minutos, eu terei feito 600 consultas no banco de dados, isso sem considerar os INSERTS para salvar novas mensagens e os UPDATES, quando a mensagem é lida. Se a aplicação tiver um acesso simultâneo de 30 pessoas, no mesmo período de tempo eu terei processado mais de 10 mil consultas ao banco de dados. Por mais que eu possa sugerir ao meu cliente escalar a memória, é muito desperdício de recursos sendo que o processo pode ser todo otimizado.
Pensando nisso, a versão 2 do sistema de mensagens, começou a trabalhar de forma semelhante ao que o MongoDB faz no node.js. Não era viável usar diretamente o node.js por causa da estrutura do servidor, então criei uma solução especifica para o sistema de mensagens:
A segunda versão da funcionalidade de mensagens da BeautyConnect
Para economizar recursos, comecei a salvar as mensagens em arquivos JSON, mais simples, leves e rápidos de ler, salvando no banco de dados apenas os logs das conversas, e assim, consegui reduzir drasticamente o uso de recursos economizando o uso de banco de dados. Agora se 2 pessoas conversarem por 5 minutos, eu terei um uso de zero consultas ao banco de dados. O resultado final do sistema de mensagens:
Próximo passos:
Apesar de ter funcionado, ainda quero melhorar esse sistema, talvez, criando um ambiente externo do principal apenas para gerenciar as mensagens, e ai usar um servidor dedicado node.js com express.js por exemplo. Mas a principal lição aqui, é que ao pensar em desenvolvermos qualquer aplicação nos dias de hoje, temos sempre que levar em conta a escala e uso de recursos, já que teremos várias pessoas utilizando ao mesmo tempo nosso aplicativo ou plataforma, antes de pensarmos em sugerir ao nossos clientes “contratarem mais memórias e servidores mais potentes”, será que estamos usando os recursos disponíveis da melhor maneira possível?
Fontes e referências
WhatsApp-Engenharia Inside-1 (Suraj Kumar) https://medium.com/codingurukul/whatsapp-engineering-inside-1-1ef4845ff784
Behind the scenes of Chat Applications (Sudaraka Jayathilaka) https://medium.com/@sudarakayasindu/behind-the-scenes-of-chat-applications-38634f584758
Erlang at Facebook: A Facebook Chat Architecture, Eugene Letuchy