Development

Registros de Comunicação

Este sistema armazena todos os registros de pedido/resposta emitidos durante o processamento de qualquer mensagem de SMS A2P. Por Milan Mimica

December 11 2015

Escopo

A plataforma de mensageria da Infobip movimenta cerca de 250M de transações por dia. São 250M de mensagens de SMS recebidas do cliente, faturadas, encaminhadas, adaptadas (se necessário) e submetidas a uma operadora. Além disso, também há os relatórios de entrega, que são enviados e submetidos de volta ao cliente. São, ao menos, 6 pares de pedidos e respostas feitos através de uma rede, que utiliza várias APIs em (às vezes) 4 protocolos completamente diferentes - apenas para processar uma única mensagem. Tudo isso, se tudo correr bem e não forem necessárias novas tentativas. E estamos falando somente de comunicação externa – não estamos considerando comunicação interna. Além disso, algumas mensagens são relacionadas e analisá-las como mensagens individuais não nos dá uma visão completa.

Já deu para perceber que é um enorme desafio manter todas as operações de rede em controle. O departamento de suporte precisa esclarecer rapidamente as dúvidas tanto do cliente quanto das operadoras. Para isso, ele precisa de uma ferramenta que levante todos os pedidos/respostas emitidos durante o processamento de qualquer mensagem. Isso, porque saber exatamente o que foi submetido pelo cliente e como foi encaminhado para a operadora, é o ponto de partida para solucionar possíveis problemas.

Distribuição de registros

A palavra “distribuição” soa agradável. É um termo que está na moda. De alguma forma, instintivamente, queremos distribuir tudo. Mas vamos ver como realmente é um sistema de distribuição de registro.

O que temos aqui são serviços separados para cada protocolo de mensageria, tanto para o cliente quanto para a operadora. Cada serviço lida com seus próprios registros, normalmente, armazenando-os na memória e escrevendo-os em um disco buffer circular. Como os serviços são desenvolvidos por equipes diferentes, é preciso dedicação para unificar o aparecimento de interfaces web para o gerenciamento dos registros. Para facilitar o trabalho do suporte, os serviços expõem os registros através de suas APIs e uma interface de administração centralizada é introduzida em um local no qual seja possível visualizar os registros de todos os serviços. Fazer todos os serviços inserirem os registros em um sistema de armazenamento de registro, como o Graylog, é um ótimo passo para a unificação - e centralização. O Graylog é bom. Escala bem e faz o trabalho. É o principal dentro do elasticsearch. Armazena os registros de mensagens com um metadado de palavras-chave indexado. A interface web é um pouco rígida no início, mas você se acostuma. Ele também possui algumas funcionalidades de analytics.

O problema é que esses registros não se relacionam. Os 6 pares de pedidos/respostas são totalmente independentes entre si. Requer uma pesada análise e a extração manual de identificadores de correlação da base de dados da plataforma de processamento interno, apenas para ligar os vários registros de comunicação de uma única mensagem. Isso sem mencionar a busca pelos registros de comunicação de mensagens relacionadas. Isso ocorre, porque o lado do cliente é separado do lado da operadora. Eles não compartilham um identificador de correlação único.

Além disso, por ter limites bem definidos de extensão dos serviços, os serviços da operadora não têm nenhuma informação sobre os do cliente e vice-versa. Ou seja, os serviços da operadora não sabem de qual cliente veio a mensagem que estão processando. Isso é chamado de separação de conceitos e, geralmente, é bom. Só não funciona bem para registros, porque os serviços da operadora não podem enriquecer os registros com alguns metadados de clientes que ajudariam a relacioná-los. Além disso, esses serviços não sabem nada sobre as relações entre as mensagens - porque não precisam dessa informação. Apenas a plataforma de processamento interno faz isso, mas não possui comunicação externa e, portanto, não produz registros. Isso significa que nossos registros não podem ter relação com os metadados associados a eles.

Uma forma de resolver isso seria fazer com que os serviços produzissem os registros e os inserissem na comunicação interna em direção à plataforma de processamento interna. A plataforma pode enriquecer os registros com os metadados e enviá-los para um armazenador de registros. Isso poderia funcionar, mas não é certo. É preciso ter preciosos recursos de processamento e “distrair” a plataforma de suas tarefas de negócios.

Apresentando o UUID

Bem, não é nada revolucionário. Compreendemos que cada mensagem precisa de um único ID – UUID (Universally Unique Identifier) associado logo que entra no sistema e é preciso enviar este ID com a mensagem ao próximo serviço na cadeia de processamento. Em seguida, cada serviço que produz os registros pode anexar esse ID para registrar metadados. Agora é fácil! Já é possível relacionar vários registros de uma única mensagem. Mas...

Emparelhando relatórios de entrega

Não demorou muito para você perceber que há um problema. Basta checar nos registros, o aviso de que estão faltando os relatórios de entrega. Mais uma vez, o problema está na separação de conceitos e, novamente, não queremos rompê-la, pois concordamos que é algo bom. Os serviços que lidam com um protocolo específico podem enviar uma mensagem recebida da plataforma e tratar do relatório de entrega. Mas emparelhar um relatório de entrega em uma mensagem é mais complexo do que se pode imaginar. É, claramente, o problema da plataforma. Ainda assim, queremos que o serviço que recebeu o relatório de entrega produza o registro. No entanto, no recebimento da entrega, ainda não é possível saber com qual mensagem ela será emparelhada (ou se será emparelhada com todas!). Sendo assim, o serviço não sabe qual UUID será anexada ao registro.

Conectando mensagens relacionadas(concatenadas)

Como dito anteriormente, algumas mensagens são relacionadas. Normalmente, são longas mensagens de SMS transferidas individualmente, mas que são processadas e exibidas no celular como uma única mensagem. Às vezes, também ocorrem divisões e fusões e, por isso, há tipos de relações, como: uma-para-várias, várias-para-uma e várias-para-várias. Também seria bom que as mensagens relacionadas tivessem registros, porque, às vezes, é preciso olhar todas as mensagens como se fossem únicas. O problema é que apenas a plataforma interna de processamento conhece a relação entre as mensagens e é lá que ocorrem as divisões e fusões. Os serviços que cuidam da comunicação externa não sabem nada sobre as relações. Eles lidam com cada mensagem individualmente e cada uma tem o seu próprio UUID.

Outra fonte de relação é o processamento em massa. O cliente pode enviar várias mensagens em uma solicitação HTTP. O serviço que cuida do HTTP analisará o pedido e transmitirá várias mensagens na plataforma, mas registrará apenas um pedido e uma resposta. Ele gerará um UUID para registrar a solicitação HTTP e um novo UUID para cada mensagem gerada neste pedido.

Gráficos salvadores

É claro que precisamos armazenar as relações entre UUIDs em algum lugar. Precisamos poder buscar todos os registros relacionados ao consultar os registros de uma única mensagem. Por exemplo, vejamos uma relação mais complexa, mas não incomum. Temos um envio do cliente (UUID-100), contendo duas mensagens longas (UUID-200 e UUID-210) que, posteriormente, foram divididas em mais mensagens e submetidas à operadora (UUID-201, UUID-202, UUID-211, UUID-212). Em seguida, recebemos uma entrega em massa, contendo relatórios de entrega de todas as partes enviadas da mensagem (UUID-300).

Surpreendentemente, é um gráfico. Claro, é possível se esforçar e armazená-lo em um banco de dados relacionado ou transformá-lo em json em um banco de dados de documentos. Mas hoje, existem as bases de dados gráficas. Vamos usar a ferramenta certa para o trabalho! Sempre que uma nova relação ou divisão/fusão acontece, enviamos um pequeno gráfico para um banco de dados gráfico. Escolhemos o Neo4j, porque o marketing dele é muito bom – é fácil para realizar conferências e doa livros e camisetas. O software também não é ruim. Você paga para agrupar e HA, mas para registros pode usar a versão gratuita. Um único Neo4j em uma CPU 16 comporta 100M nodes com 150M relações, que precisam de somente 15GB de armazenamento. O problema do Neo4j é que, mesmo deletando os nodes, a memória ou uso de disco não são liberados. Assim, você precisa limpar os dados de vez em quando.

A partir de agora, quando procuramos os registros de uma mensagem, pegamos o UUID da mensagem e buscamos todos os UUIDs relacionados a ela no Neo4j. Depois, buscamos os registros no Graylog com os mesmos UUIDs. É importante buscar somente UUIDs relevantes, não o gráfico inteiro. Por exemplo, se queremos os registros da mensagem UUID-200, só precisamos buscar os registros UUID-100, UUID-200, UUID-201, UUID-202 e UUID-300. A ramificação UUID-21x é irrelevante. O truque é usar diferentes tipos de relação ao conectar mensagens em massa e partes de mensagens. Em seguida, pode ser feita uma consulta simples no Neo4j cypher query para buscar os UUIDs relacionados.

O resultado é cada serviço enviar seus próprios registros de comunicação. Além disso, qualquer parte do sistema que criou uma nova relação será responsável pela publicação dessas informações. Os conceitos são bem separados, registrados, relacionados e armazenados em sistemas dedicados, onde podem ser procurados, eventualmente. (Por Milan Mimica, Engenheiro de Software / Líder de Equipe)