“Andando com meus sapatos” - espere, eles estão marcados?

Desde 2019, a Rússia possui uma lei sobre rotulagem obrigatória. A lei não se aplica a todos os grupos de produtos e as datas de entrada em vigor da rotulagem obrigatória para grupos de produtos são diferentes. Tabaco, calçado e medicamentos serão os primeiros a serem sujeitos a rotulagem obrigatória; outros produtos serão adicionados posteriormente, por exemplo, perfumes, têxteis e leite. Esta inovação legislativa impulsionou o desenvolvimento de novas soluções informáticas que permitirão acompanhar toda a cadeia de vida de um produto, desde a produção até à compra pelo consumidor final, a todos os participantes no processo: tanto o próprio Estado como todas as organizações que vendem bens com rotulagem obrigatória.

No X5, o sistema que rastreará mercadorias etiquetadas e trocará dados com o estado e fornecedores é denominado “Marcus”. Vamos contar em ordem como e quem o desenvolveu, qual é sua pilha de tecnologia e por que temos algo do que nos orgulhar.

“Andando com meus sapatos” - espere, eles estão marcados?

Alta carga real

“Marcus” resolve muitos problemas, o principal deles é a interação de integração entre os sistemas de informação X5 e o sistema de informação estadual para produtos rotulados (GIS MP) para rastrear a movimentação de produtos rotulados. A plataforma também armazena todos os códigos de etiquetagem recebidos por nós e todo o histórico da movimentação desses códigos entre os objetos, além de ajudar a eliminar a reclassificação de produtos etiquetados. Usando o exemplo dos produtos do tabaco, que foram incluídos nos primeiros grupos de produtos rotulados, apenas um camião de cigarros contém cerca de 600 maços, cada um dos quais com o seu código único. E a tarefa do nosso sistema é rastrear e verificar a legalidade dos movimentos de cada embalagem entre armazéns e lojas e, em última análise, verificar a admissibilidade da sua venda ao comprador final. E registramos cerca de 000 mil transações em dinheiro por hora, e também precisamos registrar como cada pacote chegou à loja. Assim, tendo em conta todos os movimentos entre objetos, esperamos dezenas de milhares de milhões de registos por ano.

Equipe M

Apesar de Marcus ser considerado um projeto dentro do X5, ele está sendo implementado usando uma abordagem de produto. A equipe trabalha de acordo com Scrum. O projeto começou no verão passado, mas os primeiros resultados só vieram em outubro - nossa própria equipe foi totalmente montada, a arquitetura do sistema foi desenvolvida e os equipamentos foram adquiridos. Agora a equipe conta com 16 pessoas, seis das quais estão envolvidas no desenvolvimento backend e frontend, três das quais estão envolvidas na análise do sistema. Mais seis pessoas estão envolvidas em testes manuais, de carga, automatizados e manutenção de produtos. Além disso, contamos com um especialista em SRE.

Não apenas os desenvolvedores escrevem código em nossa equipe; quase todos os caras sabem programar e escrever autotestes, carregar scripts e scripts de automação. Damos especial atenção a isto, uma vez que mesmo o suporte ao produto requer um elevado nível de automação. Procuramos sempre aconselhar e ajudar colegas que não programaram antes, e dar-lhes algumas pequenas tarefas para trabalharem.

Devido à pandemia do coronavírus, transferimos toda a equipe para trabalho remoto; a disponibilidade de todas as ferramentas para gestão do desenvolvimento, o fluxo de trabalho construído em Jira e GitLab possibilitaram passar facilmente desta etapa. Os meses passados ​​remotamente mostraram que a produtividade da equipe não foi prejudicada; para muitos, o conforto no trabalho aumentou, só faltou a comunicação ao vivo.

Reunião de equipe remota

“Andando com meus sapatos” - espere, eles estão marcados?

Reuniões durante o trabalho remoto

“Andando com meus sapatos” - espere, eles estão marcados?

Pilha de tecnologia da solução

O repositório padrão e ferramenta de CI/CD para X5 é GitLab. Nós o usamos para armazenamento de código, testes contínuos e implantação em servidores de teste e produção. Também utilizamos a prática de revisão de código, quando pelo menos 2 colegas precisam aprovar alterações feitas pelo desenvolvedor no código. Os analisadores de código estático SonarQube e JaCoCo nos ajudam a manter nosso código limpo e garantir o nível necessário de cobertura de testes unitários. Todas as alterações no código devem passar por essas verificações. Todos os scripts de teste executados manualmente são automatizados posteriormente.

Para a implementação bem-sucedida dos processos de negócios da “Marcus”, tivemos que resolver uma série de problemas tecnológicos, cada um deles em ordem.

Tarefa 1. A necessidade de escalabilidade horizontal do sistema

Para resolver esse problema, escolhemos uma abordagem de arquitetura de microsserviços. Ao mesmo tempo, foi muito importante compreender as áreas de responsabilidade dos serviços. Procuramos dividi-los em operações comerciais, levando em consideração as especificidades dos processos. Por exemplo, a aceitação em armazém não é uma operação muito frequente, mas de grande envergadura, durante a qual é necessário obter rapidamente do regulador estadual informações sobre as unidades de mercadorias aceites, cujo número numa entrega chega a 600000 , verifique a admissibilidade de aceitação deste produto no armazém e devolva todas as informações necessárias para o sistema de automação do armazém. Mas o envio dos armazéns tem uma intensidade muito maior, mas ao mesmo tempo opera com pequenos volumes de dados.

Implementamos todos os serviços sem estado e até tentamos dividir as operações internas em etapas, usando o que chamamos de autotópicos Kafka. É quando um microsserviço envia uma mensagem para si mesmo, o que permite equilibrar a carga em operações que consomem mais recursos e simplifica a manutenção do produto, mas falaremos mais sobre isso mais tarde.

Decidimos separar os módulos para interação com sistemas externos em serviços separados. Isso possibilitou solucionar o problema de troca frequente de APIs de sistemas externos, praticamente sem impacto nos serviços com funcionalidade de negócios.

“Andando com meus sapatos” - espere, eles estão marcados?

Todos os microsserviços são implantados em um cluster OpenShift, o que resolve o problema de dimensionamento de cada microsserviço e nos permite não usar ferramentas de descoberta de serviços de terceiros.

Tarefa 2. A necessidade de manter uma carga elevada e uma troca de dados muito intensa entre os serviços da plataforma: Somente durante a fase de lançamento do projeto, são realizadas cerca de 600 operações por segundo. Esperamos que esse valor aumente para 5000 operações/s à medida que os pontos de venda se conectem à nossa plataforma.

Este problema foi resolvido com a implantação de um cluster Kafka e o abandono quase total da interação síncrona entre os microsserviços da plataforma. Isto requer uma análise muito cuidadosa dos requisitos do sistema, uma vez que nem todas as operações podem ser assíncronas. Ao mesmo tempo, não apenas transmitimos eventos através do corretor, mas também transmitimos todas as informações comerciais necessárias na mensagem. Assim, o tamanho da mensagem pode atingir várias centenas de kilobytes. O limite de tamanho da mensagem no Kafka exige que prevejamos com precisão o tamanho da mensagem e, se necessário, os dividimos, mas a divisão é lógica, relacionada às operações de negócios.
Por exemplo, dividimos em caixas as mercadorias que chegam de carro. Para operações síncronas, microsserviços separados são alocados e testes de carga completos são realizados. Usar o Kafka nos apresentou outro desafio - testar a operação do nosso serviço levando em consideração a integração do Kafka torna todos os nossos testes unitários assíncronos. Resolvemos esse problema escrevendo nossos próprios métodos utilitários usando o Embedded Kafka Broker. Isso não elimina a necessidade de escrever testes unitários para métodos individuais, mas preferimos testar casos complexos usando Kafka.

Muita atenção foi dada ao rastreamento de logs para que seu TraceId não fosse perdido quando ocorressem exceções durante a operação de serviços ou ao trabalhar com lote Kafka. E se não houve problemas especiais com o primeiro, no segundo caso seremos forçados a registrar todos os TraceIds que acompanham o lote e selecionar um para continuar o rastreamento. Então, ao pesquisar pelo TraceId original, o usuário descobrirá facilmente com qual o rastreamento continuou.

Tarefa 3. A necessidade de armazenar uma grande quantidade de dados: Mais de 1 bilhão de rótulos por ano somente para tabaco chegam ao X5. Eles exigem acesso constante e rápido. No total, o sistema deve processar cerca de 10 mil milhões de registos do histórico de movimentação destas mercadorias rotuladas.

Para resolver o terceiro problema, foi escolhido o banco de dados NoSQL MongoDB. Construímos um fragmento de 5 nós e cada nó possui um conjunto de réplicas de 3 servidores. Isso permite dimensionar o sistema horizontalmente, adicionando novos servidores ao cluster e garantindo sua tolerância a falhas. Aqui encontramos outro problema - garantir a transacionalidade no cluster Mongo, levando em consideração o uso de microsserviços escaláveis ​​horizontalmente. Por exemplo, uma das tarefas do nosso sistema é identificar tentativas de revenda de produtos com os mesmos códigos de rotulagem. Aqui, aparecem sobreposições com digitalizações erradas ou operações erradas por parte dos caixas. Descobrimos que essas duplicatas podem ocorrer tanto dentro de um lote Kafka sendo processado quanto dentro de dois lotes sendo processados ​​em paralelo. Assim, verificar duplicatas consultando o banco de dados não deu nada. Para cada microsserviço, resolvemos o problema separadamente com base na lógica de negócio deste serviço. Por exemplo, para cheques, adicionamos um cheque dentro do lote e processamento separado para aparecimento de duplicatas na inserção.

Para garantir que o trabalho dos usuários com o histórico de operações não afete de forma alguma o mais importante - o funcionamento de nossos processos de negócios, separamos todos os dados históricos em um serviço separado com um banco de dados separado, que também recebe informações através do Kafka . Dessa forma, os usuários trabalham com um serviço isolado sem afetar os serviços que processam os dados para as operações em andamento.

Tarefa 4: Reprocessamento e monitoramento de filas:

Em sistemas distribuídos, surgem inevitavelmente problemas e erros na disponibilidade de bancos de dados, filas e fontes de dados externas. No caso de Marcus, a origem de tais erros é a integração com sistemas externos. Era necessário encontrar uma solução que permitisse repetidas solicitações de respostas erradas com algum tempo limite especificado, mas ao mesmo tempo não parasse de processar solicitações bem-sucedidas na fila principal. Para tanto, foi escolhido o conceito denominado “nova tentativa baseada em tópico”. Para cada tópico principal são criados um ou mais tópicos de repetição para os quais são enviadas mensagens erradas e ao mesmo tempo é eliminado o atraso no processamento das mensagens do tópico principal. Esquema de interação -

“Andando com meus sapatos” - espere, eles estão marcados?

Para implementar tal esquema, precisávamos do seguinte: integrar esta solução com Spring e evitar duplicação de código. Enquanto navegamos na web, encontramos uma solução semelhante baseada no Spring BeanPostProccessor, mas nos pareceu desnecessariamente complicada. Nossa equipe criou uma solução mais simples que nos permite integrar ao ciclo Spring para criação de consumidores e, adicionalmente, adicionar Retry Consumers. Oferecemos um protótipo da nossa solução para a equipe Spring, você pode ver aqui. A quantidade de Retry Consumers e a quantidade de tentativas de cada consumidor são configuradas através de parâmetros, dependendo da necessidade do processo de negócio, e para que tudo funcione basta adicionar a anotação org.springframework.kafka.annotation.KafkaListener , que é familiar a todos os desenvolvedores Spring.

Se a mensagem não puder ser processada após todas as novas tentativas, ela irá para DLT (tópico de mensagens não entregues) usando Spring DeadLetterPublishingRecoverer. A pedido do suporte, ampliamos essa funcionalidade e criamos um serviço separado que permite visualizar mensagens incluídas em DLT, stackTrace, traceId e outras informações úteis sobre elas. Além disso, foram adicionados monitoramentos e alertas a todos os tópicos DLT, e agora, de fato, o aparecimento de uma mensagem em um tópico DLT é um motivo para analisar e corrigir um defeito. Isso é muito conveniente - pelo nome do tópico, entendemos imediatamente em que etapa do processo surgiu o problema, o que acelera significativamente a busca por sua causa raiz.

“Andando com meus sapatos” - espere, eles estão marcados?

Mais recentemente, implementámos uma interface que nos permite reenviar mensagens através do nosso suporte após eliminar as suas causas (por exemplo, restaurar a funcionalidade do sistema externo) e, claro, estabelecer o defeito correspondente para análise. É aqui que nossos autotópicos são úteis: para não reiniciar uma longa cadeia de processamento, você pode reiniciá-la a partir da etapa desejada.

“Andando com meus sapatos” - espere, eles estão marcados?

Operação da plataforma

A plataforma já está em operação produtiva, todos os dias realizamos entregas e embarques, conectamos novos centros de distribuição e lojas. Como parte do piloto, o sistema funciona com os grupos de produtos “Tabaco” e “Calçados”.

Toda a nossa equipe participa da condução de pilotos, analisa problemas emergentes e faz sugestões para melhorias em nosso produto, desde a melhoria de logs até a alteração de processos.

Para não repetirmos nossos erros, todos os casos encontrados durante o piloto são refletidos em testes automatizados. A presença de um grande número de autotestes e testes de unidade permite realizar testes de regressão e instalar um hotfix em apenas algumas horas.

Agora continuamos a desenvolver e melhorar a nossa plataforma e enfrentamos constantemente novos desafios. Se você estiver interessado, falaremos sobre nossas soluções nos artigos seguintes.

Fonte: habr.com

Adicionar um comentário