Microsserviços e o custo real da rede que ninguém calcula

Microsserviços e o custo real da rede que ninguém calcula

Microsserviços viraram a resposta padrão para escalabilidade. Mas poucas equipes param pra medir o que estão trocando quando migram de chamadas em memória para chamadas de rede.

3 de junho de 2026

Tem gente que acha que microsserviços são só "serviços menores". Outros tratam como um endpoint, um banco e um deploy independente. A promessa é quebrar o monólito em pedaços, colocar um HTTP entre eles, e ter uma arquitetura moderna no diagrama.

Mas o que você fez, na prática, foi trocar uma chamada de memória por uma chamada de rede.

E rede não é memória. Rede é lenta. Rede falha. Rede tem overhead em cada camada que você nem percebe. Esse overhead parece pequeno quando você olha uma chamada isolada.

  • DNS? 0.1ms.
  • TCP handshake? 0.5ms.
  • TLS? 1ms.
  • Serialização? 0.3ms.
  • Header HTTP? 0.2ms.
  • Parsing? 0.2ms.

Tudo aparentemente insignificante. Aí você soma tudo e multiplica pela realidade.

Multiplica pelos hops. Multiplica por RPS. Multiplica pelo cenário real, aquele em que cache não tá quente, pool satura, deploy recicla instância, sidecar consome mais recurso do que deveria e o p99 dispara.

Em 1994, Peter Deutsch e seus colegas na Sun Microsystems publicaram as 8 falácias da computação distribuída. Trinta anos depois, a indústria continua cometendo os mesmos erros, só que com nomenclatura diferente: service mesh, API gateway, sidecar proxy. O problema é o mesmo. Só que agora a conta da cloud é que ficou mais caro.

De memória pra rede: 12 etapas adicionais em cada chamada

No monólito você chama um método:

ProcessPayment(order);

O CPU acessa a memória. Pega os dados. Executa a lógica. Retorna. Tempo total: 0.001ms - um microssegundo. O dado está ali. Não saiu do processo. Não passou por nenhuma camada de rede.

Agora no contexto distribuído:

await httpClient.PostAsync("http://payment-service/api/process", content);

Essa linha parece simples, mas desencadeia uma cadeia de operações.

O hostname precisa resolver pra um IP (DNS). Aí vem o three-way handshake do TCP. Se usa HTTPS, e deveria usar, mais round-trips pro TLS. Depois monta os headers HTTP, serializa o objeto em memória pra JSON, transmite os bytes, o outro lado deserializa o JSON, reconstrói o objeto em memória, processa a lógica, serializa a resposta, manda de volta, você deserializa de novo, valida, faz o mapping.

São 12 etapas pra fazer o que antes era uma chamada de função. E muita gente apresenta essa migração como se fosse simplificação.

Eu já fiz isso. Já quebrei monólito em microsserviços porque era "melhor prática". Ficou coerente no diagrama. Na prática, uma operação que era 2ms virou 45ms. O custo estava lá desde o início — eu que não tinha medido.

Anatomia do overhead: cada milissegundo importa

Números concretos, porque intuição não reduz p99.

DNS resolution: 0.1ms (cached)

Você chama http://payment-service/api/process. Esse hostname precisa virar um IP. Se tiver cacheado, 0.1ms. Se não tiver? 1-10ms. Service discovery instável? 50 a 100ms.

DNS não é instantâneo. É rápido na maioria das vezes. Mas "maioria das vezes" não é garantia em produção.

TCP handshake: 0.5ms

Three-way handshake. SYN do cliente, SYN-ACK do servidor, ACK do cliente. Dentro do mesmo datacenter, 0.5ms. Entre regiões? 10-50ms.

"Mas eu uso connection pooling!" Sim, e funciona — até a connection expirar, até o pool encher, até um novo deploy reciclar as instâncias. Aí o handshake volta.

TLS handshake: 1.0ms

Se você usa HTTPS entre serviços (e deveria), adicione 1ms pra negociação de cipher suite, troca de certificados, estabelecimento da sessão. TLS 1.3 é mais rápido que 1.2, mas não é zero.

A alternativa — usar HTTP puro dentro do cluster — existe. Mas qualquer pessoa com acesso ao cluster lê seus dados em trânsito. Avalie o risco.

HTTP headers: 0.2ms

Header não é só Content-Type. É Authorization, Accept, User-Agent, headers de tracing, e quando tem mesh tipo Istio você acumula 2 a 5KB por request.

A 10.000 requests por segundo, são 50MB/s só de headers. O overhead individual é pequeno. O overhead agregado não é.

Serialização: 0.3ms

Seu objeto Order precisa virar JSON. JsonSerializer.Serialize(order) leva 0.3ms pra um objeto médio com 20-30 propriedades. Objetos complexos com nested collections? 0.5-1ms.

Protobuf é mais rápido (~0.1ms) e menor em bytes. Mas traz consigo a manutenção de .proto files, geração de código e versionamento de schema. É um trade-off válido, mas ainda assim um trade-off.

Transmissão de rede: 0.5ms

Os bytes viajam pelo wire. Dentro do mesmo rack, 0.1ms. Mesmo datacenter, 0.5ms. Entre availability zones, 1-2ms. Entre regiões, 10-100ms.

Distribuição geográfica tem custo direto em latência. Cada hop entre serviços multiplica esse custo.

Deserialização + parsing: 0.5ms

O lado receptor lê os bytes, deserializa o JSON, valida o schema, mapeia pro modelo interno. Mais 0.5ms no caso otimista.

A conta

Soma tudo pra uma chamada dentro do mesmo datacenter:

DNS resolution:          0.1ms (cached)
TCP handshake:           0.5ms (se não reusou conexão)
TLS handshake:           1.0ms (se HTTPS)
HTTP headers:            0.2ms
Serialização (ida):      0.3ms
Transmissão (ida):       0.5ms
Processamento:           0.5ms
Serialização (volta):    0.3ms
Transmissão (volta):     0.5ms
Parsing (resposta):      0.2ms
─────────────────────────────
Total:                  ~4.1ms

Uma chamada de função: 0.001ms.
Uma chamada HTTP: ~4ms.

4.000x mais lento. Pra mesma operação lógica.

Essa é a ordem de grandeza real. E na maioria das discussões sobre migração pra microsserviços, esse número nem aparece.

Quando o overhead compensa

Não estou dizendo "nunca use microsserviços". Estou dizendo: entenda o custo antes de aceitar.

Microsserviços fazem sentido quando você tem 50+ engenheiros no mesmo produto e o merge conflict diário custa mais que a latência de rede. Ou quando possui aplicações genuinamente diferentes que precisam escalar de maneira independente — tipo um serviço de encoding de vídeo que não tem relação com o serviço de busca. Ou quando compliance exige isolamento hard de dados de saúde, financeiros, PII. Ou quando tecnologias diferentes são necessárias — ML model em Python, API em C#, stream processing em Go.

Se nenhuma dessas condições existe, o que você tem é um monólito distribuído. Todo o overhead de rede, nenhuma vantagem organizacional.

A alternativa que merece mais atenção: o modular monolith. Módulos com boundaries claros, interfaces definidas, mas rodando no mesmo processo. Zero overhead de rede. ACID transactions. Um stack trace completo quando algo quebra. E quando — e se — você precisar extrair um módulo pra um serviço separado, a interface já existe.

Peter Deutsch e seus colegas não escreveram as 8 falácias pra assustar ninguém. Escreveram pra que decisões sobre distribuição fossem tomadas com dados, não com hype. Pra que, quando alguém propuser "vamos quebrar em microsserviços", a primeira pergunta seja: quanto overhead de rede estamos dispostos a aceitar? E o que ganhamos em troca?

Se a resposta for "não sei", a decisão está prematura. E não há problema nisso. Monólitos bem feitos sustentam negócios bilionários. O Shopify é um monólito. O Stack Overflow rodou anos em dois servidores.

Rede não é memória. Nunca vai ser. Cada chamada HTTP entre serviços é uma decisão arquitetural com custo real, mensurável, composto.

Meça antes de migrar. Peter Deutsch avisou em 1994. Trinta e dois anos depois, o aviso continua válido.

Confira mais:

Fique por dentro das novidades

Assine nossa newsletter e receba as últimas atualizações e artigos diretamente em seu email.

Assinar gratuitamente