Como reduzimos em ~90% o tempo de resposta de um serviço core do Will

Allan Barbosa
will bank
Published in
5 min readJul 14, 2022

Aqui no will utilizamos a abordagem de microsserviços, e como você já deve imaginar, temos muitos serviços em determinados contextos/produto. Portanto, nesse post quero compartilhar com você o resultado de uma refatoração que aplicamos em um dos serviços core que suportam o Pix do will.

Em outubro de 2021, começamos a notar um aumento significativo no tempo de resposta desse serviço. Ligamos o farol amarelo em nossos monitoramentos e acompanhamos de perto para entender o motivo desse aumento (para ver se não era algo pontual). No entanto continuou com uma certa constância, até que em fevereiro de 2022 isso começou a onerar nosso SLI de disponibilidade.

Nesse meio tempo iniciamos uma Design Doc com o objetivo de propor uma solução que reduzisse significativamente o tempo de resposta. Isso porque quanto mais rápido esse serviço fosse, mais percepção de valor nosso cliente teria do produto — afinal, essa lentidão gerava muito contact rate (indicador de negócio e termômetro da experiência do cliente).

Após o levantamento e análise do contexto geral, elencamos alguns ofensores:

  1. Arquitetura não escalável;
  2. Ausência de uma estratégia eficiente de cache;
  3. Não tolerante a falhas;
  4. Linguagem de programação.

1. Arquitetura não escalável

A falta de planejamento e tempo hábil para criar uma arquitetura evolutiva, que suportasse o crescimento do negócio ao longo do tempo, foi o primeiro sintoma que emergiu. Notamos também que era necessário entender mais a fundo aquele domínio de negócio mediante a tantas integrações de sistemas que ali existiam, para que ao final, fosse possível alcançar uma solução tolerante a falhas e resiliente.

Nesse momento tínhamos o seguinte cenário:

Uma API Core chamava outra API (Contexto A) para validar a informação da conta do cliente. No entanto, por trás do Contexto A existiam ainda mais 4 API’s nesse fluxo, resultando assim em 5 requisições HTTP — o que estava mais do que claro que iria falhar em diversos momentos, principalmente ao integrar com sistemas externos.

Architecture Blueprint versão 1

A primeira coisa que fizemos foi conversar com os especialistas de domínio para entender se existia realmente a necessidade de tantas integrações, pois olhando para o código implementado parecia existir uma certa repetição. Após alguns estudos, chegamos à conclusão que seria suficiente utilizar apenas o Contexto B para validar a informação que a API Core necessitava, então demos o primeiro passo removendo o que não era necessário.

Architecture Blueprint versão 2

Nesse momento foi possível reduzir boa parte do tempo de resposta. Contudo, não ter uma estratégia de resiliência nos incomodava muito, pois se a API Contexto A caísse teríamos novamente aumento de contact rate.

2. Estratégia de cache

Quando pensamos em desenvolvimento moderno de software, na maior parte do tempo estamos falando sobre caching.

Imagem retirada do filme Toy Story, com os personagens Woody e Buzz Lightyear e a legenda “Caching, caching everywhere”

Aqui não foi diferente: ao identificarmos que o estado da informação que a API Core consultava não sofria tanta alteração, a primeira ideia foi…

“Vamos colocar uma camada de cache e ser felizes!”

A ideia era muito boa e traria um ganho significativo no fluxo, mas esbarramos em problema de capacidade de time: a implementação dessa camada de cache não caberia no planejamento, pois tínhamos uma equipe pequena com um backlog já gigante.

Foi assim que decidimos adicionar um API Gateway com a estratégia de response cache, sendo necessário apenas alguns arquivos yaml para configurar tudo, chegando na seguinte arquitetura:

Architecture Blueprint versão 3

Basicamente configuramos:

- API Gateway Kong em modo DB-Less;
- Plugin para cache de response com Redis (TTL de 4 horas);
- Exposição de endpoints para a API Contexto A.

3. Tolerância a falhas

Reduzir conexões e adicionar a camada de cache já traria um resultado significativo, mas ainda havia a necessidade de evitar falhas em cascata, já que temos chamada HTTP para fora do contexto Core e sabemos que isso é problema (as falácias da computação distribuída estão aí para provar).

Sendo assim, decidimos utilizar o padrão Circuit Breaker que permite um fluxo mais tolerante a falhas e resiliente, que “sobrevive” quando os principais serviços que a API Core consome estiverem passando por instabilidade. Assim, o blueprint final da arquitetura ficou dessa forma:

Architecture Blueprint versão 4 — Final

4. Linguagem de programação

Optamos em testar uma nova linguagem. Sabíamos que escrevendo essa solução em Go teríamos um enorme ganho em economia de infraestrutura e startup do projeto, pois nossa solução trabalhava em média com 150MB de memória e seu startup chegava a 5 minutos (o que dificultava muito a subida/escala de novos pods no K8S).

Havia ainda outros contextos dentro do time que precisavam realizar processos concorrentes ou paralelos, tornando-se aprazível o uso de Go Routines.

De forma geral achamos Go uma linguagem com baixa curva de aprendizagem, o que nos possibilitou uma entrega muito rápida do projeto e, ao colocar em produção, atingimos números admiráveis (que compartilho na sequência).

Resultados obtidos

  • Consumo de memória reduzido em 80% - 150MB para 30MB.
  • Redução no tempo de inicialização do serviço em 99,3% - 5 minutos para 2 segundos.
  • Consumo de CPU reduzido em 97,5% - 4% para 0,1%.
  • Tamanho da imagem docker reduzido em 91,6% - 168MB para 14MB.
  • Tempo de resposta reduzido em 90,83% - 120ms para 11ms.
  • A camada de cache reutiliza 90% das requisições, evitando ir até o destino e removendo uma grande carga da API Contexto A.
  • Caso a API Contexto A fique fora do ar, o sistema Core consegue operar durante 4 horas retornando erro apenas para 10% das requisições.

Esses foram os resultados que obtivemos dessa experiência aqui dentro do will. E você, já testou algo parecido? Fique à vontade para comentar e contar pra gente!

Referências

Quer fazer parte de um time incrível, construir um banco do zero e democratizar o crédito para milhões de brasileiros? Veja nossas vagas e vem ser will!

--

--