Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Quadro do filme “Nosso Universo Secreto: A Vida Oculta da Célula”

O negócio de investimento é uma das áreas mais complexas do mundo bancário, porque não existem apenas empréstimos, financiamentos e depósitos, mas também títulos, moedas, mercadorias, derivados e todo o tipo de complexidades sob a forma de produtos estruturados.

Recentemente, temos assistido a um aumento da literacia financeira da população. Cada vez mais pessoas estão envolvidas na negociação nos mercados de valores mobiliários. As contas de investimento individuais surgiram não há muito tempo. Eles permitem que você negocie nos mercados de valores mobiliários e receba deduções fiscais ou evite o pagamento de impostos. E todos os clientes que nos procuram querem gerir a sua carteira e ver os relatórios em tempo real. Além disso, na maioria das vezes esse portfólio é multiproduto, ou seja, as pessoas são clientes de diversos ramos de negócios.

Além disso, as necessidades dos reguladores, tanto russos como estrangeiros, estão a aumentar.

Para atender às necessidades atuais e estabelecer as bases para atualizações futuras, desenvolvemos um núcleo de negócios de investimento baseado na Tarantool.

Algumas estatísticas. O negócio de investimento do Alfa-Bank oferece serviços de corretagem para pessoas físicas e jurídicas para proporcionar a oportunidade de negociação em diversos mercados de valores mobiliários, serviços de depósito para armazenamento de valores mobiliários, serviços de gestão fiduciária para pessoas físicas com capital privado e grande, serviços de emissão de valores mobiliários para outras empresas . O negócio de investimento do Alfa-Bank inclui mais de 3 mil cotações por segundo, que são baixadas de diversas plataformas de negociação. Durante a jornada de trabalho, são concluídas nos mercados mais de 300 mil transações em nome do banco ou dos seus clientes. Ocorrem até 5 mil execuções de ordens por segundo em plataformas externas e internas. Ao mesmo tempo, todos os clientes, internos e externos, desejam ver as suas posições em tempo real.

Pré-história

Desde o início da década de 2000, as nossas áreas de negócio de investimento desenvolveram-se de forma independente: negociação em bolsa, serviços de corretagem, negociação de divisas, negociação no mercado de balcão de valores mobiliários e vários derivados. Como resultado, caímos na armadilha dos poços funcionais. O que é isso? Cada linha de negócios possui seus próprios sistemas que duplicam as funções uns dos outros. Cada sistema possui seu próprio modelo de dados, embora operem com os mesmos conceitos: transações, instrumentos, contrapartes, cotações, etc. E à medida que cada sistema evoluiu de forma independente, surgiu um zoológico diversificado de tecnologias.

Além disso, a base de código dos sistemas já está bastante desatualizada, pois alguns produtos foram originados em meados da década de 1990. E em algumas áreas isto atrasou o processo de desenvolvimento e houve problemas de desempenho.

Requisitos para uma nova solução

As empresas perceberam que a transformação tecnológica é vital para um maior desenvolvimento. Recebemos tarefas:

  1. Colete todos os dados de negócios em um armazenamento único e rápido e em um único modelo de dados.
  2. Não devemos perder ou alterar essas informações.
  3. É necessário versionar os dados, pois a qualquer momento o regulador poderá solicitar estatísticas de anos anteriores.
  4. Não devemos apenas trazer alguns SGBD novos e modernos, mas criar uma plataforma para resolver problemas de negócios.

Além disso, nossos arquitetos estabeleceram suas próprias condições:

  1. A nova solução deve ser de classe empresarial, ou seja, já deve ser testada em algumas grandes empresas.
  2. O modo operacional da solução deve ser de missão crítica. Isso significa que devemos estar presentes em vários data centers simultaneamente e sobreviver com calma à interrupção de um data center.
  3. O sistema deve ser escalável horizontalmente. O fato é que todos os nossos sistemas atuais são escalonáveis ​​apenas verticalmente e já estamos atingindo o teto devido ao baixo crescimento da potência do hardware. Portanto, chegou o momento em que precisamos de um sistema escalável horizontalmente para sobreviver.
  4. Entre outras coisas, disseram-nos que a solução tinha de ser barata.

Seguimos o caminho padrão: formulamos os requisitos e entramos em contato com o departamento de compras. A partir daí recebemos uma lista de empresas que, em geral, estão prontas para fazer isso por nós. Contamos a todos sobre o problema e recebemos uma avaliação das soluções de seis deles.

No banco não acreditamos na palavra de ninguém; gostamos de testar tudo nós mesmos. Portanto, uma condição obrigatória do nosso concurso foi a aprovação nos testes de carga. Formulamos tarefas de teste de carga e três em cada seis empresas já concordaram em implementar uma solução de protótipo baseada em tecnologias in-memory às suas próprias custas para testá-la.

Não vou contar como testamos tudo e quanto tempo demorou, vou apenas resumir: o melhor desempenho em testes de carga foi demonstrado por uma solução protótipo baseada em Tarantool da equipe de desenvolvimento do Grupo Mail.ru. Assinamos um acordo e iniciamos o desenvolvimento. Eram quatro pessoas do Grupo Mail.ru e do Alfa-Bank três desenvolvedores, três analistas de sistemas, um arquiteto de soluções, um proprietário de produto e um Scrum master.

A seguir contarei como nosso sistema cresceu, como evoluiu, o que fizemos e por que exatamente isso.

Desenvolvimento

A primeira pergunta que nos fizemos foi como obter dados dos nossos sistemas atuais. Decidimos que o HTTP era bastante adequado para nós, porque todos os sistemas atuais se comunicam enviando XML ou JSON por HTTP.

Usamos o servidor HTTP integrado ao Tarantool porque não precisamos encerrar sessões SSL e seu desempenho é suficiente para nós.

Como já disse, todos os nossos sistemas vivem em modelos de dados diferentes e, na entrada, precisamos trazer o objeto para o modelo que nós mesmos descrevemos. Era necessária uma linguagem que permitisse a transformação dos dados. Escolhemos Lua imperativa. Executamos todo o código de conversão de dados em uma sandbox - este é um local seguro além do qual o código em execução não vai. Para fazer isso, simplesmente carregamos o código necessário, criando um ambiente com funções que não podem bloquear ou descartar nada.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Após a conversão, os dados devem ser verificados quanto à conformidade com o modelo que estamos criando. Discutimos durante muito tempo qual deveria ser o modelo e que linguagem usar para descrevê-lo. Escolhemos o Apache Avro porque a linguagem é simples e conta com suporte do Tarantool. Novas versões do modelo e do código personalizado podem ser colocadas em operação várias vezes ao dia, mesmo sob carga ou sem carga, a qualquer hora do dia, e se adaptam às mudanças com muita rapidez.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Após verificação, os dados devem ser salvos. Fazemos isso usando vshard (temos réplicas de fragmentos geograficamente dispersas).

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Além disso, a especificidade é tal que a maioria dos sistemas que nos enviam dados não se importam se os recebemos ou não. É por isso que implementamos uma fila de reparo desde o início. O que é isso? Se por algum motivo um objeto não passar por transformação ou verificação de dados, ainda assim confirmamos o recebimento, mas ao mesmo tempo salvamos o objeto na fila de reparo. Ele é consistente e está localizado no data warehouse principal da empresa. Escrevemos imediatamente uma interface de administrador para ele, várias métricas e alertas. Como resultado, não perdemos dados. Mesmo que algo tenha mudado na fonte, se o modelo de dados mudou, iremos detectá-lo imediatamente e poderemos nos adaptar.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Agora você precisa aprender como recuperar dados salvos. Analisamos cuidadosamente nossos sistemas e vimos que a pilha clássica de Java e Oracle contém necessariamente algum tipo de ORM que converte dados de relacionais em objetos. Então, por que não dar imediatamente objetos aos sistemas na forma de um gráfico? Por isso, adotamos alegremente o GraphQL, que atendeu a todas as nossas necessidades. Ele permite que você receba dados na forma de gráficos e extraia apenas o que você precisa no momento. Você pode até mesmo versionar a API com bastante flexibilidade.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Quase imediatamente percebemos que os dados que estávamos extraindo não eram suficientes. Criamos funções que podem ser vinculadas a objetos no modelo – essencialmente, campos calculados. Ou seja, anexamos ao campo uma determinada função que, por exemplo, calcula o preço médio da cotação. E o consumidor externo que solicita os dados nem sabe que se trata de um campo calculado.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Implementou um sistema de autenticação.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Então percebemos que vários papéis se cristalizaram em nossa decisão. Um papel é uma espécie de agregador de funções. Normalmente, as funções têm diferentes perfis de uso de equipamentos:

  • T-Connect: lida com conexões de entrada, CPU limitada, baixo consumo de memória, sem estado.
  • IB-Core: transforma os dados que recebe via protocolo Tarantool, ou seja, opera com tabelas. Também não armazena estado e é escalonável.
  • Armazenamento: armazena apenas dados, não utiliza nenhuma lógica. Esta função implementa as interfaces mais simples. Escalável graças ao vshard.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Ou seja, por meio de funções, desacoplamos diferentes partes do cluster umas das outras, que podem ser dimensionadas independentemente umas das outras.

Portanto, criamos uma gravação de fluxo de dados transacionais assíncronos e uma fila de reparo com interface administrativa. A gravação é assíncrona do ponto de vista comercial: se tivermos a garantia de gravar dados para nós mesmos, não importa onde, então iremos confirmá-los. Se não for confirmado, algo deu errado e os dados precisam ser enviados. Esta é a gravação assíncrona.

Teste

Desde o início do projeto, decidimos que tentaríamos implementar o desenvolvimento orientado a testes. Escrevemos testes de unidade em Lua usando a estrutura tarantool/tap e testes de integração em Python usando a estrutura pytest. Ao mesmo tempo, envolvemos desenvolvedores e analistas na escrita de testes de integração.

Como usamos o desenvolvimento orientado a testes?

Se quisermos algum recurso novo, tentamos escrever um teste para ele primeiro. Quando descobrimos um bug, primeiro escrevemos um teste e só depois o corrigimos. No começo é difícil trabalhar assim, há incompreensão por parte dos funcionários, até mesmo sabotagem: “Vamos consertar isso rapidamente agora, fazer algo novo e depois cobrir com testes”. Só que esse “depois” quase nunca chega.

Portanto, você precisa se forçar a escrever testes primeiro e pedir a outros que o façam. Acredite, o desenvolvimento orientado a testes traz benefícios mesmo no curto prazo. Você sentirá que sua vida se tornou mais fácil. Sentimos que 99% do código agora está coberto por testes. Parece muito, mas não temos problemas: testes são executados em cada commit.

Porém, o que mais gostamos são os testes de carga; consideramos-os o mais importante e realizamo-los regularmente.

Vou contar uma pequena história sobre como realizamos a primeira etapa de teste de carga de uma das primeiras versões. Instalamos o sistema no laptop do desenvolvedor, ligamos a carga e obtivemos 4 mil transações por segundo. Bom resultado para um laptop. Instalamos em um banco de carga virtual de quatro servidores, mais fraco que em produção. Implantado ao mínimo. Nós o executamos e obtemos um resultado pior do que em um laptop em um thread. Conteúdo de choque.

Ficamos muito tristes. Observamos a carga do servidor, mas descobrimos que eles estão ociosos.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Chamamos os desenvolvedores e eles nos explicam, gente que vem do mundo Java, que o Tarantool é single-threaded. Ele só pode ser usado efetivamente por um núcleo do processador sob carga. Em seguida, implantamos o máximo possível de instâncias do Tarantool em cada servidor, ligamos a carga e já recebemos 14,5 mil transações por segundo.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Deixe-me explicar novamente. Devido à divisão em funções que utilizam recursos de forma diferente, nossas funções responsáveis ​​pelo processamento de conexões e transformação de dados carregam apenas o processador, e são estritamente proporcionais à carga.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Neste caso, a memória foi usada apenas para processar conexões de entrada e objetos temporários.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Pelo contrário, nos servidores de armazenamento, a carga do processador aumentou, mas muito mais lentamente do que nos servidores que processam conexões.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
E o consumo de memória cresceu em proporção direta à quantidade de dados carregados.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool

Serviços

Para desenvolver nosso novo produto especificamente como plataforma de aplicativos, criamos um componente para implantação de serviços e bibliotecas nele.

Os serviços não são apenas pequenos pedaços de código que operam em alguns campos. Eles podem ser estruturas bastante grandes e complexas que fazem parte de um cluster, verificam dados de referência, executam lógica de negócios e retornam respostas. Também exportamos o esquema de serviço para GraphQL, e o consumidor recebe um ponto de acesso universal aos dados, com introspecção em todo o modelo. É muito confortável.

Como os serviços contêm muito mais funções, decidimos que deveria haver bibliotecas nas quais moveríamos o código usado com frequência. Nós os adicionamos ao ambiente seguro, tendo verificado previamente que não prejudica nada para nós. E agora podemos atribuir ambientes adicionais a funções na forma de bibliotecas.

Queríamos ter uma plataforma não só de armazenamento, mas também de computação. E como já tínhamos um monte de réplicas e fragmentos, implementamos uma espécie de computação distribuída e chamamos de redução de mapa, porque ficou semelhante à redução de mapa original.

Sistemas antigos

Nem todos os nossos sistemas legados podem nos chamar por HTTP e usar GraphQL, embora suportem o protocolo. Portanto, criamos um mecanismo que permite que os dados sejam replicados nesses sistemas.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Se algo mudar para nós, gatilhos únicos são acionados na função Storage e a mensagem com as alterações vai para a fila de processamento. Ele é enviado para um sistema externo usando uma função de replicador separada. Esta função não armazena estado.

Novas melhorias

Como você lembra, do ponto de vista comercial, fizemos gravação assíncrona. Mas então perceberam que não seria suficiente, pois existe uma classe de sistemas que precisa receber imediatamente uma resposta sobre o status da operação. Então estendemos nosso GraphQL e adicionamos mutações. Eles se encaixam organicamente no paradigma existente de trabalho com dados. Para nós, este é um ponto único de leitura e escrita para outra classe de sistemas.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Percebemos também que os serviços por si só não seriam suficientes para nós, porque são relatórios bastante pesados ​​que precisam ser construídos uma vez por dia, por semana, por mês. Isso pode levar muito tempo e os relatórios podem até bloquear o loop de eventos do Tarantool. Portanto, criamos funções separadas: agendador e executor. Os corredores não armazenam estado. Eles executam tarefas pesadas que não podemos calcular na hora. E a função do agendador monitora o cronograma de inicialização dessas tarefas, descrito na configuração. As próprias tarefas são armazenadas no mesmo local que os dados comerciais. Quando chega a hora certa, o agendador pega a tarefa, entrega para algum executor, que a conta e salva o resultado.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Nem todas as tarefas precisam ser executadas de acordo com um cronograma. Alguns relatórios precisam ser lidos sob demanda. Assim que esse requisito chega, uma tarefa é criada no sandbox e enviada ao executor para execução. Depois de algum tempo, o usuário recebe uma resposta assíncrona informando que tudo foi calculado e o relatório está pronto.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Inicialmente, aderimos ao paradigma de armazenar todos os dados, versioná-los e não excluí-los. Mas na vida, de vez em quando você ainda precisa deletar alguma coisa, principalmente alguma informação bruta ou intermediária. Com base na expiração, criamos um mecanismo para limpar o armazenamento de dados desatualizados.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool
Também entendemos que mais cedo ou mais tarde surgirá uma situação em que não haverá espaço suficiente para armazenar dados na memória, mas mesmo assim os dados deverão ser armazenados. Para esses fins, em breve faremos armazenamento em disco.

Como construímos o núcleo do negócio de investimento do Alfa-Bank com base no Tarantool

Conclusão

Começamos com a tarefa de carregar dados em um único modelo e passamos três meses desenvolvendo-o. Tínhamos seis sistemas de fornecimento de dados. Todo o código de transformação em um único modelo tem cerca de 30 mil linhas em Lua. E a maior parte do trabalho ainda está por vir. Às vezes falta motivação das equipes vizinhas e há muitas circunstâncias que dificultam o trabalho. Se você alguma vez enfrentar uma tarefa semelhante, multiplique o tempo que lhe parece normal para sua implementação por três ou até quatro.

Lembre-se também de que os problemas existentes nos processos de negócios não podem ser resolvidos com um novo SGBD, mesmo que seja muito produtivo. O que eu quero dizer? No início do nosso projeto, criamos nos clientes a impressão de que agora traremos um novo banco de dados rápido e viveremos! Os processos serão mais rápidos, tudo ficará bem. Na verdade, a tecnologia não resolve os problemas dos processos de negócios, porque os processos de negócios são pessoas. E você precisa trabalhar com pessoas, não com tecnologia.

O desenvolvimento orientado a testes pode ser doloroso e demorado nos estágios iniciais. Mas o efeito positivo disso será perceptível mesmo no curto prazo, quando você não precisar fazer nada para realizar testes de regressão.

É extremamente importante realizar testes de carga em todos os estágios de desenvolvimento. Quanto antes você notar alguma falha na arquitetura, mais fácil será corrigi-la, o que economizará muito tempo no futuro.

Não há nada de errado com Lua. Qualquer pessoa pode aprender a escrever nele: desenvolvedor Java, desenvolvedor JavaScript, desenvolvedor Python, front-end ou back-end. Até nossos analistas escrevem sobre isso.

Quando falamos sobre o fato de não termos SQL, isso assusta as pessoas. “Como você obtém dados sem SQL? Isso é possível? Certamente. Em um sistema de classes OLTP, o SQL não é necessário. Existe uma alternativa na forma de algum tipo de linguagem que imediatamente leva você de volta a uma visão orientada a documentos. Por exemplo, GraphQL. E existe uma alternativa na forma de computação distribuída.

Se você entende que precisará escalar, projete sua solução no Tarantool de forma que ela possa ser executada em paralelo em dezenas de instâncias do Tarantool. Se você não fizer isso, será difícil e doloroso mais tarde, já que o Tarantool só pode usar efetivamente um núcleo de processador.

Fonte: habr.com

Adicionar um comentário