Do monolito ao container: quebrar sem parar a operação

Como sair de um monolito sem reescrever tudo: conteinerizar primeiro, achar as costuras certas, extrair na ordem de menor risco e resolver o banco compartilhado.

Equipe Solvefy 7 min de leitura

A conversa sobre modernizar um monolito costuma começar pelo lugar errado: pela reescrita. Alguém propõe reconstruir o sistema em microsserviços, o projeto ganha um prazo de nove meses, e dezoito meses depois existem dois sistemas incompletos — o antigo, que ninguém quer mais tocar, e o novo, que ainda não atende tudo. Reescrita completa é a forma mais confiável de gastar muito e entregar pouco. Existe um caminho incremental, e ele começa sem quebrar nada.

Primeiro passo: conteinerizar sem dividir

O primeiro movimento não é separar o monolito. É empacotá-lo como está.

Isso parece pouco ambicioso e entrega muito mais do que se imagina: ambiente reprodutível, fim do "na minha máquina funciona", implantação previsível, possibilidade de subir várias instâncias, retorno rápido de versão anterior. Nada disso exige tocar na arquitetura da aplicação.

E, principalmente, é aqui que você descobre o que está realmente acoplado ao servidor. Um monolito que roda em container revela, em poucos dias, todas as suposições que ele fazia sobre a máquina: o arquivo que ele escrevia em disco local, a sessão que ele guardava em memória, a configuração que estava num arquivo editado à mão em produção. Cada uma dessas descobertas é um pré-requisito da divisão futura, e é bem melhor resolvê-las com o sistema inteiro do que no meio de uma extração.

Os pré-requisitos que a conteinerização revela

Antes de pensar em dividir, cinco coisas precisam estar resolvidas:

  1. Configuração externa. Nada de valor fixo no código ou em arquivo editado no servidor. Tudo por variável de ambiente ou serviço de configuração, com segredo em cofre.
  2. Aplicação sem estado. O processo pode ser morto e recriado a qualquer momento, sem perda. Isso implica sessão fora da memória local — em Redis ou em cookie assinado.
  3. Nada escrito em disco local. Upload de arquivo vai para armazenamento de objetos. Disco de container é efêmero por definição.
  4. Log na saída padrão, não em arquivo dentro do container. Coleta e retenção são responsabilidade da plataforma.
  5. Migração de banco desacoplada da subida da aplicação. Se a aplicação aplica migração ao iniciar, subir três instâncias simultaneamente é um problema. Migração é etapa própria do processo de implantação.

Esses cinco itens valem por si mesmos, mesmo que você nunca divida o monolito. É a maior parte do benefício por uma fração do esforço.

Achar as costuras certas

Monolito não se divide em qualquer lugar. A divisão boa acontece onde já existe uma fronteira natural, e há três sinais confiáveis:

  • Acoplamento baixo com o resto. Um módulo que conversa com o núcleo por poucas chamadas bem definidas é candidato. Um módulo que compartilha dezenas de estruturas de dado não é.
  • Perfil de escala diferente. Processamento de imagem que precisa de muita CPU em rajadas, dentro do mesmo processo que serve páginas web, é candidato óbvio — separar permite escalar cada um pelo que ele precisa.
  • Ritmo de mudança diferente. Parte que muda toda semana acoplada a parte que muda uma vez por ano é atrito permanente de implantação.

E um sinal de que não é hora de dividir: se você não consegue descrever a fronteira sem usar "e também", a fronteira não existe ainda. Nesse caso, o trabalho é organizar o módulo dentro do monolito primeiro. Fronteira mal escolhida gera duas peças que precisam ser implantadas juntas — o pior dos dois mundos.

A ordem de extração que reduz risco

Comece pelo que é menos crítico e tem fronteira mais clara. Candidatos que costumam funcionar bem como primeira extração:

  • Envio de notificação — e-mail, mensagem, notificação por aplicativo. Assíncrono por natureza, fronteira evidente, falha tolerável.
  • Geração de documento ou relatório, que é pesado, esporádico e independente.
  • Processamento de mídia, com perfil de recurso muito diferente do resto.
  • Integração com terceiro, que já é uma fronteira externa.

O que não extrair primeiro: autenticação e o núcleo do domínio. São as partes mais acopladas e mais críticas, e errar ali custa caro. Elas ficam para quando a equipe já tiver experiência com o processo e com a operação distribuída.

EtapaO que fazerRisco
1Conteinerizar o monolito como estáBaixo
2Resolver configuração, estado, log e migraçãoBaixo
3Implantar rastreamento distribuído e métricasBaixo
4Extrair um serviço periférico e assíncronoMédio
5Extrair o segundo, já com o processo conhecidoMédio
6Separar dados do serviço extraídoAlto
7Reavaliar: vale continuar dividindo?

A etapa 7 é a mais importante e a mais ignorada. Depois de duas ou três extrações, você tem dados reais sobre o custo operacional de cada serviço adicional. Muitas equipes descobrem, corretamente, que o ponto ideal é um monolito bem organizado mais três ou quatro serviços — e não trinta.

O banco de dados é a parte difícil

Extrair código é a parte fácil. O que realmente separa os serviços é o dado, e é aqui que a maioria das migrações para. O atalho tentador é manter o banco compartilhado: o serviço novo acessa as mesmas tabelas do monolito.

Isso funciona por um tempo e cria o pior resultado possível — o monolito distribuído. Você passou a ter a complexidade operacional de vários serviços e continuou com o acoplamento de um só: mudança de esquema quebra dois serviços, nenhum dos dois pode evoluir sozinho, e não há como implantar separadamente.

Caminhos que funcionam de verdade, do mais simples ao mais elaborado:

  1. O serviço extraído não acessa o banco direto. Ele pede ao monolito, por API. É um passo intermediário legítimo e resolve o acoplamento de esquema.
  2. Separar tabelas primeiro, dentro do mesmo banco. Definir que só um dos lados escreve em cada tabela, com o outro consultando por API. A separação lógica antecede a física.
  3. Escrita dupla temporária, durante a transição, com uma fonte de verdade clara e um mecanismo de reconciliação. Requer cuidado, porque escrita dupla sem reconciliação gera divergência silenciosa.
  4. Captura de mudanças do banco, publicando eventos que o novo serviço consome. É o caminho mais robusto para dado que precisa existir nos dois lados.

Observabilidade antes da divisão, não depois

Num monolito, depurar é ler um log e uma pilha de chamadas. Com serviços separados, uma requisição atravessa três processos, e sem rastreamento distribuído você fica sem saber onde o tempo foi gasto ou onde a falha começou.

A regra é simples: implante rastreamento distribuído antes da primeira extração, não depois de sentir falta. Junto com ele, identificador de correlação propagado entre serviços e log estruturado. É a etapa 3 da tabela por um motivo — sem ela, as etapas seguintes acontecem no escuro.

O custo que ninguém coloca na conta

Cada serviço novo traz uma parcela de custo permanente que não aparece no plano do projeto: mais um pipeline, mais um conjunto de alertas, mais uma dependência a versionar, mais uma peça no plano de recuperação, mais um lugar onde a autenticação entre serviços precisa funcionar.

Uma orientação prática de dimensionamento: se a sua equipe não tem gente suficiente para que cada serviço tenha alguém que o conheça bem, você tem serviços demais. Time de cinco pessoas operando quinze microsserviços passa mais tempo cuidando de infraestrutura do que entregando produto — e isso é o oposto do objetivo.

Monolito bem organizado, conteinerizado, com implantação automatizada e observabilidade decente é uma arquitetura perfeitamente respeitável. A divisão precisa ser justificada por um problema concreto — escala desigual, ritmo de mudança incompatível, autonomia de equipes —, não pela arquitetura ideal descrita numa apresentação.

Erros comuns

  • Propor reescrita completa em vez de migração incremental.
  • Dividir antes de resolver configuração, estado e log.
  • Manter banco compartilhado entre monolito e serviço novo.
  • Extrair primeiro a autenticação ou o núcleo do domínio.
  • Dividir onde não há fronteira, criando duas peças que se implantam juntas.
  • Deixar rastreamento distribuído para depois da primeira extração.
  • Escrita dupla sem reconciliação, gerando divergência silenciosa.
  • Migração de banco disparada pela subida da aplicação.
  • Mais serviços do que a equipe consegue operar.
  • Não reavaliar depois das primeiras extrações.

Onde a Solvefy/Cloud entra

Em consultoria DevOps, conduzimos essa migração pelo caminho incremental: conteinerizamos o que existe, resolvemos os pré-requisitos que aparecem, implantamos observabilidade e só então extraímos — começando pelo periférico, com o desenho de dados definido antes do código. E somos diretos quando a resposta é parar: para muitos clientes, o destino certo é um monolito bem empacotado com poucos serviços ao lado, não uma malha de microsserviços que a equipe não tem tamanho para operar.

Quer modernizar sem parar a operação? Fazemos um diagnóstico gratuito, sem compromisso, em solvefy.cloud.

Solvefy/Cloud — Infraestrutura que cresce com você.

Faça agora o seu diagnóstico e orçamento

Inicie com um diagnóstico gratuito da sua infraestrutura e receba uma proposta personalizada — com escopo, cronograma e valores.