DEV Community

Cover image for [BR] Arquiteturas híbridas - entrelaçando monólitos, microsserviços e serviços distribuídos
Scarlet Rose
Scarlet Rose

Posted on

[BR] Arquiteturas híbridas - entrelaçando monólitos, microsserviços e serviços distribuídos

Vejo muitas pessoas (algumas até mesmo abominam a ideia, no mesmo naipe daquele pessoal que odeia modinhas novas em memes) receosas a respeito da construção de serviços distribuídos e microsserviços, muitas até imaginando um processo big-bang, que demandaria custos absurdos e causaria problemas difíceis de serem resolvidos.

Mas não é bem assim, a implantação de microsserviços não precisa necessariamente ser uma operação atômica, e nem mesmo definitiva! A arquitetura de uma solução não necessita seguir apenas um padrão em sua integridade, e nem precisa se manter a mesma permanentemente.

Esses são os motivos pelos quais eu acredito no poder das arquiteturas distribuídas e microsserviços:

  • Uma solução completa é uma união de vários artefatos, um monólito que começou hoje pode, em alguns meses, ter uma funcionalidade crítica que precise ser abstraída para um serviço separado e escalada individualmente, e tá tudo bem!
  • É possível que o time de engenharia e arquitetura entre em um consenso de que para exercer determinada função, é necessário começar com serviços distribuídos do zero, database não é o gargalo aqui, assincronismo e recursos sim, e tá tudo bem.
  • Talvez existam centenas (ou milhares) de desenvolvedores que atuam em um mesmo produto (incomum, mas WOW!) e manter o código-fonte em um mesmo projeto pode causar desde conflitos de código até uma (e diga-se de passagem) longa fila de espera para que uma squad específica possa colocar seu trecho de código em produção

Escala é sobre pessoas. Desenvolvimento é uma atividade sociológica. E não, esses padrões de arquitetura não são uma bala de prata, nenhum é, afinal o importante é ter sua aplicação disponível em produção, gerando receita e agregando a vida de seus clientes.

Entendendo o que é uma arquitetura híbrida

Quando falamos de arquitetura de software, pensamos em algo como um monólito bem estruturado utilizando algo como onion architecture ou arquitetura hexagonal para que todas as suas peças estejam no lugar certo, ou até mesmo em uma estrutura de serviços escaláveis de maneira isolada que se conectam de maneira distribuída a um mesmo banco de dados, ou por fim, a famosa arquitetura de microsserviços, onde todas as operações são isoladas com o objetivo de evitar a manutenção de um único ponto de falha. Acontece que na prática não é bem assim. Fora de empresas tecnológicas que já são consolidadas a uns bons anos, arquiteturas que podem ser consideradas "perfeitas" por muitos são raras e (de maneira esperada) não vão existir, ou ao menos não vão funcionar como todos imaginariam. No contexto deste artigo, irei considerar uma arquitetura híbrida como aquela arquitetura que está se adaptando a um novo desafio, mas não deixarei de informar que também podem ser arquiteturas que já venceram certo desafio e encontraram o "nirvana" onde o nível de estabilidade é alto ao mesmo tempo que fogem de conceitos tradicionais e enraizados.

Em resumo, arquitetura híbrida é aquela que utiliza dois ou mais conceitos para alcançar determinado objetivo de escalonamento. Pense num monólito de onde foram abstraídos 3 serviços moderados que ainda utilizam um mesmo banco de dados e 2 serviços críticos que contam com nível de isolamento algo, com seus próprios bancos de dados. Isso é uma arquitetura híbrida, fazer algo acontecer a partir da orquestração de diversos conceitos - otimizando custos, cargas de trabalho, tempo de desenvolvimento e disponibilidade no que realmente precisa, e isso não é fácil de fazer.

Vantagens de se usar uma arquitetura híbrida

Não, não existem vantagens no estilo "bala de prata". O que existem são vantagens situacionais que podem ser observadas em momentos onde você precisa escalar X, mas não precisa escalar Y e Z, vamos a um exemplo mais concreto.

Gateway de pagamentos

Um gateway de pagamentos, surgido da necessidade de oferecer uma interface simples de pagamentos para empresas que buscam contingência e diversificação nas suas transações começou como um monólito, lá, internamente o mesmo era dividido pelas seguintes funcionalidades que acessavam um único banco de dados:

  • Users - funcionalidade interna de gerenciamento de usuários, nesse caso, os clientes. Conta com sub-módulos de autenticação, perfis internos, preferências e suporte;
  • Wallet - carrega o ledger e a montagem de operações únicas que a plataforma vai fazer para garantir integridade em todos os pagamentos, além de conter uma ou mais "balanças" para controlar o faturamento dos clientes bem como seus objetivos;
  • Payments - carrega as implementações de diferentes integrações bancárias, criptomoedas, fintechs e até outros gateways de pagamentos em uma interface única, fácil de usar para o cliente;
  • Receipts - responsável por triangular as informações de Payments e Wallet e executar operações como geração de notas fiscais, demandas do banco central (e outros órgãos envolvidos) e gerar arquivos de comprovante e receitas dos mais diversos tipos além de manter arquivos de outras plataformas acessíveis para operações internas.

Parece que temos aqui um sistema hipoteticamente coeso que irá tratar de pagamentos, a stack nesse caso pode ser qualquer uma, desde que seja levado em consideração que o backend é um monólito e o banco de dados é único. Perfeito, temos a nossa base.

Imagine que a solução funciona perfeitamente, mas a partir do primeiro ano de oferecimento do serviço a quantidade de clientes comece a subir e o servidor comece a obter gargalos, uma reunião do time de negócio com o time técnico é feita e as dores são repassadas:

  • Nós estamos tendo reclamações dos clientes, os pagamentos instantâneos estão demorando mais do que o aceitável para serem realizados!
  • A plataforma não está se mantendo em pé e isso se agrava deliberadamente nos inícios e finais dos meses, o que pode estar acontecendo?

Então, após uma pesquisa técnica mais detalhada a equipe de tecnologia conseguiu encontrar os gargalos:

  • O nosso serviço de Receipts está consumindo muita memória e CPU do servidor e isso se agrava em épocas de pagamento já que a demanda de pagamentos em geral aumenta também os comprovantes e receitas fazendo com que a geração de arquivos seja superior, isso está afetando todo o ecossistema.

Então, após um minuto de silêncio, alguém da sala menciona:

  • E se aumentássemos a CPU e memória que contratamos no nosso servidor? Acredito que os problemas seriam resolvidos!

Essa parecia ser uma boa solução, mas alguém apontou:

  • De acordo com os dados passados pela equipe de negócios, estamos crescendo em alta velocidade, fora que no próximo mês teremos época de Black Friday. Um aumento agora não serviria de nada pois os custos desse tipo de escalonamento logo iria ficar para trás.

Mais um segundo de silêncio, então surgiu outra sugestão:

  • Podemos então, montar um cluster e colocar o nosso servidor como uma peça instanciável, assim, teremos um load balancer e um escalonamento sob demanda que será mais barato do que o aumento de recursos.

A pergunta era: quão barato? E isso foi logo respondido pelo engenheiro de SRE:

  • Na verdade, não compensaria, pois os custos ainda seriam altos visto que uma instância pode atender a uma demanda X, cuja renda prevista mínima seria Y, mas o custo total do FinOps seria Z, trazendo um lucro mínimo e desperdício, visto que vamos estar escalando também serviços desnecessários.

Então, após mais algum tempo de pensamento sobre o que era possível fazer, foi sugerida uma conclusão de meio termo que se mostrou viável:

  • Nossos serviços estão bem desacoplados, que tal se mantêssemos nosso servidor como está, mas fizéssemos a abstração de Receipts para um serviço distribuído? A reutilização de código tornaria os custos de um novo repositório quase nulos e dessa forma nós conseguimos escalar o serviço de maneira isolada com uma taxa de desperdício muito menor.

Foi então que o time concordou com a solução: era rápida, prática, não alteraria nenhum padrão que já era pré-existente na codebase e permitiria escalonamento virtualmente infinito somente para o que fosse necessário. Perfeito! A solução foi implantada e os resultados se mostraram positivos: a solução como um todo se mostrou estável e robusta. Seguindo a mesma lógica, o serviço Payments logo foi abstraído para ter o seu próprio escalonamento, também com a criação de um cache próprio para não exaurir o banco de dados e a solução agora se via ainda mais rápida e confiável.

Depois de alguns meses e um crescimento considerável do produto e da empresa, os agentes de negócio contataram mais uma vez o time técnico, dessa vez com dores diferentes:

  • O crescimento está ótimo, mas como efeito colateral, nós não conseguimos mais utilizar ferramentas como Excel e PowerBI para acessar os dados de forma sólida e atender nossos clientes de maneira ágil, o que podemos fazer?

Era um caso um pouco mais complexo, de fato a quantidade de dados no banco havia decolado (e muito) e os dados do cache de Payments não eram confiáveis nem suficientes, uma vez que eram simplesmente transacionais e expirava. Após mais uma reunião técnica, foi desvendado um novo caminho para a resolução desse problema: a criação de um microsserviço isolado, isso é, com banco de dados próprio, otimizado para resolver o problema que estava na mesa: análise e depuração de dados. O setup foi montado junto ao time de negócios e um analista de dados foi contratado para desvendar o caminho das pedras, no fim, foi decidido o seguinte:

  • Um microsserviço isolado seria criado, com seu escalonamento limitado, uma vez que não seria utilizado por uma vasta gama de clientes, mas mantendo sua independência para que não fosse afetado por picos externos na aplicação principal;
  • Um banco de dados do estilo time series seria criado para facilitar que os dados pudessem contar uma história de forma que os agentes de negócio pudessem realizar planejamentos mais coesos e ajudar os clientes de maneira mais assertiva;
  • Um pequeno worker (serviço isolado) foi criado para que, de maneira automática, pudesse sincronizar os dados criados no banco de dados com o novo banco de time series, fazendo as adaptações de modelagem necessárias para extrair os melhores insights. Tudo isso com uma disponibilidade de D+1, que no momento é o que o time de negócios precisa para poder atuar de maneira ágil (o suficiente).

E assim vemos os finalmentes, uma arquitetura sólida (para as necessidades do negócio), efêmera (que sempre se altera de acordo com o que for preciso) e híbrida (que não seguirá cegamente um padrão de evolução apenas porque está descrito em algum livro, mas que se importa com nuances e sabe se organizar).

Tecnologias e o que utilizar em cada caso

Muitas pessoas têm esse tipo de dúvida, a questão é que não existe uma "receita de bolo" para atuar nesse tipo de caso, até porque é possível que uma decisão tomada de maneira precipitada acabe prejudicando o sistema como um todo de uma maneira quase irreversível. A chave aqui é a comunicação, se você estiver em um lugar que valoriza experiências acima de certificações, conversar, fazer reuniões e papos técnicos é o melhor caminho. Afinal, entender do seu Cláudio da arquitetura que se lembra do fatídico incidente em 2009 onde uma implementação incerta quebrou a produção causando 300.000 dólares de prejuízo em vendas e foi resolvida de maneira calma, com um post-mortem coeso é melhor do que levar em consideração uma decisão tomada em 15 minutos totalmente enviesada do Adriano da engenharia que tem 3 certificações AWS e 2 certificações Azure, mas nunca participou de um war room nem colocou nada significante em produção. (Nomes e situações completamente fictícios)

No mais, existe um post no meu LinkedIn que não se relaciona diretamente com o assunto mas pode te dar insights valiosos sobre como tomar esse tipo de decisão. Veja aqui e até a próxima!

Ah e se você estiver se perguntando sobre eu não ter mencionado "o que é um pod e um container", ou algo como "utilize o EKS da seguinte maneira", o motivo é claro: nesse artigo, busquei utilizar da linguagem genérica a minha força, afinal, para cada solução existem N problemas e como eu sempre digo, não existe bala de prata. Mesmo assim, buscarei abordar assuntos mais nichados em artigos futuros.

Top comments (0)