icardb
Microsserviços vs monólito: critérios objetivos para escolher a arquitetura
Voltar para artigosPROGRAMAÇÃO

Microsserviços vs monólito: critérios objetivos para escolher a arquitetura

Por Lucas Mendes 7 min de leitura

A discussão monólito versus microsserviços costuma ser apresentada como evolução linear: primeiro o monólito, depois a "arquitetura madura" de serviços distribuídos. A realidade de produção é menos romântica. Microsserviços trocam complexidade de código por complexidade operacional — e essa troca só compensa em contextos específicos. Este artigo apresenta os trade-offs mensuráveis e um critério de decisão baseado em restrições reais.

Definições sem marketing

Monólito é uma aplicação implantada como uma única unidade: um processo (ou um conjunto de réplicas do mesmo processo) com uma base de código e, normalmente, um banco de dados. Monólito modular é a mesma unidade de deploy, mas com fronteiras internas explícitas entre módulos de domínio, impedindo acoplamento indevido. Microsserviços são processos independentes, cada um com deploy, escala e, idealmente, dados próprios, comunicando-se por rede.

O termo "microsserviço" não descreve tamanho de código, e sim autonomia de deploy e de dados. Dois serviços que compartilham o mesmo banco formam, na prática, um monólito distribuído — o pior dos dois mundos.

Comparação objetiva

AspectoMonólitoMonólito modularMicrosserviços
Deploy1 artefato, tudo ou nada1 artefato, tudo ou nadaIndependente por serviço
Latência de chamadaChamada em processo (~ns)Chamada em processo (~ns)Rede (~ms) + serialização
Consistência de dadosTransações ACID locaisTransações ACID locaisConsistência eventual / sagas
ObservabilidadeLogs e stack traces locaisLogs locais + fronteiras clarasTracing distribuído obrigatório
Custo de infra mínimo1 app + 1 banco1 app + 1 bancoOrquestrador, gateway, service discovery
Escala granularReplica tudoReplica tudoReplica só o serviço quente
Onboarding de devUm repositório para entenderUm repositório, módulos clarosN repositórios + contratos
Falha parcialRaro (processo cai inteiro)RaroComum; exige retry, timeout, circuit breaker

O custo oculto da distribuição

Cada chamada que sai do processo vira uma chamada de rede. Isso introduz latência adicional (típico de 0,5 a 5 ms dentro de uma mesma região de nuvem, contra nanossegundos em memória), falhas parciais e a necessidade de tratar timeouts. O código abaixo ilustra o tratamento mínimo que uma chamada entre serviços exige — código que simplesmente não existe em um monólito:

ts
async function buscarPedido(id: string, tentativas = 3): Promise<Pedido> {
  for (let i = 0; i < tentativas; i++) {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 2000);
    try {
      const res = await fetch(`https://servico-pedidos/internal/pedidos/${id}`, {
        signal: controller.signal,
        headers: { "x-request-id": crypto.randomUUID() },
      });
      if (res.status >= 500) throw new Error(`upstream ${res.status}`);
      if (!res.ok) throw new Error(`erro definitivo ${res.status}`); // não retenta 4xx
      return (await res.json()) as Pedido;
    } catch (err) {
      if (i === tentativas - 1) throw err;
      await new Promise((r) => setTimeout(r, 100 * 2 ** i)); // backoff exponencial
    } finally {
      clearTimeout(timeout);
    }
  }
  throw new Error("inalcançável");
}

Multiplique esse padrão por dezenas de integrações e some tracing distribuído, contratos versionados, filas para comunicação assíncrona e estratégias de consistência como sagas. O catálogo de padrões em microservices.io lista dezenas deles — cada um é um problema que o monólito não tem.

Quando microsserviços realmente compensam

  • Times grandes e independentes: quando 5+ equipes precisam fazer deploy sem se bloquear, a fronteira de serviço alinha-se à fronteira organizacional (Lei de Conway).
  • Requisitos de escala muito díspares: um endpoint de processamento de imagem consumindo 100x mais CPU que o resto do sistema justifica escala isolada.
  • Requisitos de disponibilidade distintos: um módulo crítico (ex.: checkout) pode precisar de isolamento de falhas que o restante não justifica.
  • Deploys frequentes e independentes: se o negócio exige releases diários por time sem janela de coordenação.

Quando o monólito (modular) é a escolha certa

Para a maioria dos produtos em estágio inicial e médio, o monólito modular entrega quase todos os benefícios organizacionais sem o custo operacional. A receita prática: um repositório, módulos por domínio com APIs internas explícitas, proibição de import cruzado fora da API do módulo, e um schema por domínio no banco. Se um dia um módulo precisar virar serviço, a fronteira já existe.

text
src/
  modules/
    catalogo/        # só expõe index.ts (API pública do módulo)
      index.ts       # export { listarProdutos, obterProduto }
      internal/      # repositórios, entidades — proibido importar de fora
    pedidos/
      index.ts       # importa de "modules/catalogo", nunca de internal/
      internal/
    pagamentos/
      index.ts
      internal/

Sinais de que você extraiu serviços cedo demais: deploys que precisam ser coordenados entre repositórios, endpoints chamando 3+ serviços para montar uma resposta, e desenvolvedores rodando 6 processos locais para testar uma feature.

Critério de decisão em 4 perguntas

  1. Quantos times independentes farão deploy neste sistema? Se a resposta é 1 ou 2, monólito modular.
  2. Existe um componente com perfil de carga 10x diferente do resto? Se não, monólito.
  3. O time opera hoje com maturidade em observabilidade, CI/CD e infra como código? Se não, microsserviços vão amplificar o problema, não resolver.
  4. O domínio é bem compreendido o suficiente para desenhar fronteiras estáveis? Fronteiras erradas em serviços custam 10x mais para corrigir do que em módulos.

Conclusão

Arquitetura é gestão de trade-offs, não busca por sofisticação. O monólito modular é o ponto de partida correto para a maioria dos sistemas; microsserviços são uma resposta organizacional e de escala, não um selo de qualidade. Empresas como a Amazon documentaram publicamente o caminho inverso — consolidar serviços de volta em processos únicos quando a distribuição não se pagava. Decida com métricas de time e de carga, não com tendência.

Perguntas frequentes

+Monólito não escala?

Escala horizontalmente como qualquer processo: réplicas atrás de um load balancer. A limitação é granularidade — você replica a aplicação inteira, mesmo que só 10% dela esteja quente. Para a maioria das cargas, isso é suficiente e muito mais barato.

+Posso começar com microsserviços para não precisar migrar depois?

É a estratégia mais arriscada. Fronteiras de serviço desenhadas antes de o domínio amadurecer quase sempre ficam erradas, e mover lógica entre serviços é muito mais caro do que entre módulos. Comece modular e extraia quando a dor for real e mensurável.

+O que é um monólito distribuído?

Um conjunto de serviços que compartilham banco de dados ou que só conseguem fazer deploy juntos. Tem todo o custo operacional da distribuição sem nenhum benefício de autonomia — o cenário a evitar.

+Quantos microsserviços são 'microsserviços demais'?

Não existe número mágico, mas uma heurística útil: se um desenvolvedor não consegue listar os serviços e suas responsabilidades de cabeça, ou se cada feature toca 4+ serviços, a granularidade passou do ponto.

Fontes consultadas

Revisão editorial: publicado em . Última revisão em . Conteúdo educativo, sem patrocínio das ferramentas citadas.

Crédito da imagem: Foto: Lucas Mendes / Gerado por IA (Licença Editorial)

Leia também