Desde o ano passado, hackathons começaram a ser organizados em nossa empresa. A primeira competição desse tipo foi muito bem-sucedida, escrevemos sobre isso no
artigo . A segunda hackathon foi realizada em fevereiro de 2019 e não teve menos sucesso. O organizador
escreveu recentemente sobre os objetivos deste último.
Foi dada aos participantes uma tarefa bastante interessante, com total liberdade na escolha de uma pilha de tecnologia para sua implementação. Era necessário implementar uma plataforma de decisão para uma implantação conveniente de funções de pontuação do cliente que pudessem trabalhar em um fluxo rápido de aplicativos, suportar cargas pesadas e o próprio sistema ser escalonado com facilidade.
A tarefa não é trivial e pode ser resolvida de várias maneiras, como vimos na demonstração das apresentações finais dos projetos dos participantes. Havia 6 equipes de 5 pessoas no hackathon, todos os participantes tinham bons projetos, mas nossa plataforma acabou sendo a mais competitiva. Temos um projeto muito interessante, sobre o qual gostaria de falar neste artigo.
Nossa solução é uma plataforma baseada na arquitetura Serverless no Kubernetes, que reduz o tempo necessário para trazer novos recursos à produção. Ele permite que os analistas escrevam código em um ambiente conveniente para eles e o implantem no produto sem a participação de engenheiros e desenvolvedores.
O que é pontuação?
Tinkoff.ru, como muitas empresas modernas, tem pontuação de clientes. A pontuação é um sistema de avaliação de clientes baseado em métodos estatísticos de análise de dados.
Por exemplo, um cliente solicita um empréstimo ou abre uma conta IP conosco. Se planejamos conceder um empréstimo a ele, você precisa avaliar sua solvência e, se a conta for de private equity, precisará ter certeza de que o cliente não realizará transações fraudulentas.
Essas decisões são baseadas em modelos matemáticos que analisam os dados do próprio aplicativo e os dados do nosso armazenamento. Além da pontuação, métodos estatísticos semelhantes também podem ser usados no trabalho do serviço para gerar recomendações individuais sobre novos produtos para nossos clientes.
O método dessa avaliação pode receber uma variedade de dados de entrada. E, em algum momento, podemos adicionar um novo parâmetro à entrada que, de acordo com a análise de dados históricos, aumentará a conversão do uso do serviço.
Armazenamos muitos dados sobre o relacionamento com os clientes e o volume dessas informações está em constante crescimento. Para que a pontuação funcione, o processamento de dados também requer regras (ou modelos matemáticos) que permitem que você decida rapidamente quem aprovará o aplicativo, quem recusar e quem mais oferecerá alguns produtos para avaliar seu interesse potencial.
Para esta tarefa, já usamos o
sistema de tomada de decisão especializado
IBM WebSphere ILOG JRules BRMS , que, com base nas regras definidas por analistas, tecnólogos e desenvolvedores, decide se aprova um produto bancário específico para um cliente ou se recusa.
Existem muitas soluções prontas no mercado, tanto modelos de pontuação quanto sistemas de tomada de decisão. Usamos um desses sistemas em nossa empresa. Mas o negócio está crescendo, diversificando, o número de clientes e o número de produtos oferecidos estão aumentando e, junto com isso, estão surgindo idéias de como melhorar o processo de tomada de decisão existente. Certamente as pessoas que trabalham com o sistema existente têm muitas idéias sobre como torná-lo mais simples, melhor, mais conveniente, mas às vezes as idéias externas são úteis. A fim de coletar idéias sólidas, um Novo Hackathon foi organizado.
Tarefa
O hackathon foi realizado em 23 de fevereiro. Foi oferecida aos participantes uma missão de combate: desenvolver um sistema de tomada de decisão, que deveria atender a várias condições.
Disseram-nos como o sistema existente funciona e que dificuldades surgem durante sua operação, bem como quais objetivos de negócios a plataforma em desenvolvimento deve buscar. O sistema deve ter um rápido tempo de colocação no mercado das regras em desenvolvimento para que o código de trabalho dos analistas entre em produção o mais rápido possível. E para o fluxo de aplicativos que chega, o tempo de tomada de decisão deve tender ao mínimo. Além disso, o sistema desenvolvido deve ser capaz de realizar vendas cruzadas, a fim de dar ao cliente a oportunidade de comprar outros produtos da empresa, se forem aprovados por nós e um interesse potencial por parte do cliente.
É claro que em uma noite é impossível escrever um projeto pronto para o lançamento que certamente entrará em produção, e todo o sistema é bastante difícil de cobrir, por isso fomos solicitados a implementar pelo menos parte dele. Foram estabelecidos vários requisitos que o protótipo deve atender. Pode-se tentar cobrir todos os requisitos como um todo e elaborar em detalhes seções individuais da plataforma desenvolvida.
Quanto à tecnologia, todos os participantes tiveram total liberdade de escolha. Foi possível usar qualquer conceito e tecnologia: streaming de dados, aprendizado de máquina, fornecimento de eventos, big data e outros.
Nossa decisão
Após uma pequena sessão de brainstorming, decidimos que a solução FaaS seria ideal para a tarefa.
Para esta solução, foi necessário encontrar uma estrutura sem servidor adequada para implementar as regras do sistema de tomada de decisão desenvolvido. Como o Kubernetes é usado ativamente no gerenciamento de infraestrutura em Tinkoff, examinamos várias soluções prontas com base nele, falarei mais sobre isso mais tarde.
Para encontrar a solução mais eficaz, analisamos o produto desenvolvido através dos olhos de seus usuários. Os principais usuários do nosso sistema são analistas envolvidos no desenvolvimento de regras. As regras devem ser implantadas no servidor ou, como no nosso caso, implantadas na nuvem para posterior tomada de decisão. Da perspectiva do analista, o fluxo de trabalho é o seguinte:
- O analista grava um script, regra ou modelo de ML com base nos dados do repositório. Como parte do hackathon, decidimos usar o Mongodb, mas a escolha do sistema de armazenamento não é importante aqui.
- Após testar as regras desenvolvidas em dados históricos, o analista coloca seu código no painel de administração.
- Para garantir a versão, todo o código irá para os repositórios Git.
- Por meio do painel de administração, será possível implantar o código na nuvem como um módulo sem servidor funcional separado.
Os dados de origem dos clientes devem passar por um serviço de Enriquecimento especializado, projetado para enriquecer a solicitação inicial com dados do repositório. Era importante implementar esse serviço de maneira que ele funcionasse com um único repositório (do qual o analista coleta dados ao desenvolver as regras) para manter uma estrutura de dados unificada.
Mesmo antes do hackathon, decidimos sobre a estrutura sem servidor que usaremos. Existem algumas tecnologias no mercado que implementam essa abordagem. As soluções de arquitetura Kubernetes mais populares são Fission, Open FaaS e Kubeless. Existe até um
bom artigo com sua descrição e análise comparativa .
Depois de pesar todos os prós e contras, optamos pela
Fissão . Essa estrutura sem servidor é bastante fácil de gerenciar e atende aos requisitos da tarefa.
Para trabalhar com a fissão, você precisa entender dois conceitos básicos: função e ambiente. Função (função) é um pedaço de código escrito em um dos idiomas para os quais existe um ambiente de fissão (ambiente).
A lista de ambientes implementados dentro da estrutura dessa estrutura inclui Python, JS, Go, JVM e muitas outras linguagens e tecnologias populares.
A fissão também é capaz de executar funções, divididas em vários arquivos, pré-empacotadas no arquivo morto. A operação de fissão no cluster Kubernetes é fornecida por pods especializados, gerenciados pela própria estrutura. Para interagir com os pods de cluster, cada função deve ser atribuída a uma rota e à qual você pode passar parâmetros GET ou solicitar corpo no caso de uma solicitação POST.
Como resultado, planejamos obter uma solução que permita aos analistas implantar scripts de regras desenvolvidos sem a participação de engenheiros e desenvolvedores. A abordagem descrita também elimina a necessidade de os desenvolvedores reescreverem o código dos analistas em outro idioma. Por exemplo, para o atual sistema de tomada de decisão que usamos, precisamos escrever regras em tecnologias e linguagens de perfil estreito, cujo escopo é extremamente limitado e também existe uma forte dependência do servidor de aplicativos, pois todos os rascunhos de regras bancárias são implementados em um único ambiente. Como resultado, para a implantação de novas regras, é necessário liberar todo o sistema.
Na solução que propusemos, não há necessidade de liberar as regras, o código é facilmente implantado com o clique de um botão. Além disso, o gerenciamento de infraestrutura no Kubernetes permite que você não pense na carga e no dimensionamento; esses problemas são resolvidos imediatamente. E o uso de um único data warehouse elimina a necessidade de comparar dados em tempo real com dados históricos, o que simplifica o trabalho do analista.
O que conseguimos
Desde que chegamos ao hackathon com uma solução pronta (em nossas fantasias), precisamos apenas converter todos os nossos pensamentos em linhas de código.
A chave do sucesso em qualquer hackathon é a preparação e um plano bem elaborado. Portanto, antes de tudo, decidimos em quais módulos nossa arquitetura de sistema será composta e em quais tecnologias usaremos.
A arquitetura do nosso projeto foi a seguinte:
Este diagrama mostra dois pontos de entrada, um analista (o principal usuário do nosso sistema) e um cliente.
O processo de trabalho está estruturado assim. O analista desenvolve a função de regra e a função de enriquecimento de dados para seu modelo, salva seu código no repositório Git e implementa seu modelo na nuvem por meio do aplicativo do administrador. Considere como a função expandida será chamada e tome decisões sobre solicitações recebidas de clientes:
- O cliente que preenche um formulário no site envia sua solicitação ao controlador. Um aplicativo chega na entrada do sistema, segundo o qual uma decisão deve ser tomada, e é registrado no banco de dados em sua forma original.
- Em seguida, uma solicitação bruta é enviada para enriquecimento, se necessário. Você pode complementar a solicitação inicial com dados de serviços externos e do repositório. A consulta avançada recebida também é armazenada no banco de dados.
- A função analítica é iniciada, que recebe uma solicitação aprimorada na entrada e fornece uma decisão, que também é registrada na loja.
Como armazenamento em nosso sistema, decidimos usar o MongoDB em vista do armazenamento documentado de dados na forma de documentos JSON, pois os serviços de aprimoramento, incluindo a solicitação inicial, agregavam todos os dados através dos controladores REST.
Então, tivemos um dia para implementar a plataforma. Distribuímos com êxito as funções, cada membro da equipe tinha sua própria área de responsabilidade em nosso projeto:
- O painel de administração do front-end para o trabalho do analista, através do qual ele pode baixar as regras do sistema de controle de versão dos scripts escritos, escolher as opções para enriquecer os dados de entrada e editar os scripts de regras online.
- Um painel de administração de back-end que inclui uma API REST para integração frontal e VCS.
- Configurando a infraestrutura no Google Cloud e desenvolvendo um serviço de enriquecimento de dados de origem.
- O módulo para integrar o aplicativo de administração à estrutura sem servidor para a implantação subsequente das regras.
- Scripts de regras para testar a integridade de todo o sistema e agregação de análises para aplicativos recebidos (decisões tomadas) para a demonstração final.
Vamos começar em ordem.
Nosso front-end foi escrito em Angular 7, usando o kit bancário de interface do usuário. A versão final do painel de administração era a seguinte:
Como não houve muito tempo, tentamos implementar apenas a funcionalidade principal. Para implantar uma função no cluster Kubernetes, você precisava selecionar um evento (um serviço para o qual você precisa implantar uma regra na nuvem) e codificar o código da função que implementa a lógica de decisão. Para cada implantação da regra para o serviço selecionado, escrevemos um log desse evento. No painel do administrador, você pode ver os logs de todos os eventos.
Todo o código de função foi armazenado em um repositório Git remoto, que também precisou ser definido no painel de administração. Para a versão do código, todas as funções foram armazenadas em diferentes ramificações do repositório. O painel do administrador também oferece a capacidade de fazer ajustes nos scripts escritos para que, antes de implantar uma função na produção, você possa não apenas verificar o código escrito, mas também fazer as alterações necessárias.
Além das funções das regras, também percebemos a possibilidade de enriquecer, passo a passo, os dados de origem usando as funções de enriquecimento, cujo código também consistia em scripts nos quais você poderia acessar o data warehouse, chamar serviços de terceiros e realizar cálculos preliminares. Para demonstrar nossa solução, calculamos o signo do cliente que saiu do aplicativo e determinamos sua operadora de celular usando um serviço REST de terceiros.
O back-end da plataforma foi escrito em Java e implementado como um aplicativo Spring Boot. Para armazenar os dados do administrador, originalmente planejamos usar o Postgres, mas, como parte do hackathon, decidimos nos limitar a um H2 simples, para economizar tempo. No back-end, a integração com o Bitbucket foi implementada para a versão das funções de enriquecimento de consultas e scripts de regras. Para integrar com repositórios Git remotos,
foi usada a biblioteca JGit , que é um tipo de wrapper sobre comandos da CLI que permite executar qualquer instrução git usando uma interface de programa conveniente. Portanto, tínhamos dois repositórios separados, para funções e regras de aprimoramento, e todos os scripts são organizados em diretórios. Por meio da interface do usuário, foi possível selecionar o último script de confirmação de uma ramificação arbitrária do repositório. Ao fazer alterações no código por meio do painel de administração, as confirmações do código modificado foram criadas nos repositórios remotos.
Para implementar nossa ideia, precisávamos de uma infraestrutura adequada. Decidimos implantar nosso cluster Kubernetes na nuvem. Nossa escolha é o Google Cloud Platform. A estrutura sem servidor Fless foi instalada no cluster Kubernetes, que implantamos no Gcloud. Inicialmente, o serviço de enriquecimento de dados de origem foi implementado por um aplicativo Java separado envolvido em um Pod dentro de um cluster k8s. Porém, após uma demonstração preliminar de nosso projeto no meio da hackathon, fomos recomendados para tornar o serviço de Enriquecimento mais flexível, a fim de oferecer uma oportunidade de escolher como enriquecer os dados brutos dos aplicativos recebidos. E não tivemos escolha senão tornar o serviço de enriquecimento também sem servidor.
Para trabalhar com o Fission, usamos a CLI da Fission, que deve ser instalada na parte superior da CLI do Kubernetes. A implantação de funções no cluster k8s é bastante simples, você só precisa atribuir uma rota interna e ingresso para a função para permitir o tráfego de entrada se for necessário acessar fora do cluster. A implantação de uma função geralmente não leva mais que 10 segundos.
Mostra final do projeto e resumo
Para demonstrar a operação do nosso sistema, colocamos em um servidor remoto um formulário simples no qual você pode solicitar um dos produtos do banco. Para a solicitação, você precisava digitar suas iniciais, data de nascimento e número de telefone.
Os dados do formulário do cliente foram para o controlador, que simultaneamente enviou aplicativos para todas as regras disponíveis, enriquecendo os dados de acordo com as condições especificadas e salvando-os em um armazenamento comum. No total, implantamos três funções de tomada de decisão para aplicativos recebidos e 4 serviços de enriquecimento de dados. Após o envio do aplicativo, o cliente recebeu nossa solução:
Além da rejeição ou aprovação, o cliente também recebeu uma lista de outros produtos para os quais enviamos solicitações em paralelo. Então, demonstramos a possibilidade de venda cruzada em nossa plataforma.
No total, três produtos bancários inventados estavam disponíveis:
- De crédito
- Brinquedo
- Hipoteca
Durante cada demonstração, implantamos funções preparadas e scripts de aprimoramento para cada serviço.
Cada regra precisava de seu próprio conjunto de dados de entrada. Portanto, para aprovar a hipoteca, calculamos o signo do zodíaco do cliente e o associamos à lógica do calendário lunar. Para aprovar o brinquedo, verificamos que o cliente era maior de idade e, para emitir um empréstimo, enviamos uma solicitação a um serviço externo aberto para determinar a operadora móvel e tomamos uma decisão sobre ele.
Tentamos tornar nossa demonstração interessante e interativa, todos os presentes poderiam ir ao nosso formulário e verificar a disponibilidade de nossos serviços imaginários para ele. E no final da apresentação, demonstramos a análise dos aplicativos recebidos, onde foi mostrado quantas pessoas usaram nosso serviço, o número de aprovações, recusas.
Para coletar análises on-line, implementamos adicionalmente a ferramenta de BI de código aberto
Metabase e a parafusamos em nosso repositório. A Metabase permite criar telas com análises baseadas nos dados em que estamos interessados, você só precisa registrar uma conexão com o banco de dados, selecionar tabelas (no nosso caso, coletas de dados desde que usamos o MongoDB) e especificar os campos de interesse para nós.
Como resultado, obtivemos um bom protótipo da plataforma de tomada de decisão e, na demonstração, cada ouvinte poderia testar pessoalmente seu desempenho. Uma solução interessante, um protótipo pronto e uma demonstração bem-sucedida nos permitiram vencer, apesar da forte concorrência diante de outras equipes. Estou certo de que, no projeto de cada equipe, você também pode escrever um artigo interessante.