Quando o APM te engana: Um milhão de requisições e um gargalo invisível no TCP

Quando o APM te engana: Um milhão de requisições e um gargalo invisível no TCP

Você entende as limitações que sua incrivel stack de observalidade tem? Não por descuido. É limitação técnica mesmo.

14 de Novembro de 2025

Um cliente processa milhões de transações de pagamento por dia. Só com um dos parceiros dele, são cerca de 1 milhão de requisições diárias.

E, deste volume, algo estranho acontecia.

Aproximadamente 1.000 requisições apresentavam mais de 3 segundos de resposta, algumas chegando a 10 segundos! E aparentemente sem nenhum padrão que pudesse determinar a causa.

No mesmo segundo em que uma transação demorava 10 segundos, outra era processada em 200 ms.

Clássico cenário de caos distribuído.

O parceiro dizia que não era problema dele.
Nosso cliente dizia que não era ele.
E ambos apontavam para um mesmo ponto de "verdade":

O APM disse que a requisição levou 10 segundos. Logo, é problema do outro lado.

E então fomos chamados.

War Room montada

Chegamos para ajudar a formar evidências sólidas o suficiente para que o parceiro dele não pudesse se "esconder".

Depois da explicação do cenário, fizemos a primeira pergunta:

Qual linguagem vocês usam?
O cliente, já sem paciência e sem entender o motivo da pergunta:
Python. Por quê?
– Como o Python gerencia conexões HTTP?
Não estou entendendo como isso ajuda.
– Queremos saber se o Python está reutilizando conexões ou se está refazendo handshake TCP a cada requisição.
Mas se isso fosse o problema, por que só algumas chamadas são lentas?

Excelente pergunta.

Respondemos:

– E se essas requisições lentas aconteceram justamente quando uma instância reiniciou e precisou refazer resolução DNS?

– E se, no momento do handshake, o servidor do parceiro estava sobrecarregado por meio segundo?

– Ou se houve uma retransmissão TCP na camada 4 que o APM não captura?

Nesse ponto o cliente parou, respirou e prestou atenção.
Finalmente estávamos falando de algo que ele nunca tinha considerado.

Afinal, qual dev olha pra rede?

O problema clássico da Observabilidade

A raiz desse problema pode estar na limitação estrutural dos sistemas de observabilidade:

O APM só vê o processo da aplicação.

Quando o código executa:

httpRequest.send()

O APM começa a contar o tempo.
Mas tudo que acontece fora do processo da aplicação e que compõe a maior parte da chamada HTTP ele não vê.

Isso inclui:

  • Resolução DNS
  • Handshake TCP (SYN, SYN/ACK, ACK)
  • Abertura da porta efêmera (ex: 62340)
  • Retransmissões de pacotes
  • Concorrência no driver de rede
  • Filas internas do kernel
  • Latência real na camada 4 ou na camada 3
  • Timeout de SYN/ACK
  • Slow start do TCP

O APM só vê o que a linguagem vê.
E a linguagem só vê o que o processo da aplicação vê.

Resultado?

Se a requisição ficou presa dentro do sistema operacional, o APM vai mentir pra você ou, no mínimo, vai te induzir ao erro.

E o parceiro, claro, também via um APM que não mostrava nada suspeito.

O pior dos mundos:
cada um com sua meia verdade e ninguém com a verdade completa.

“Ok, então vamos observar a camada do SO”

Essa é a reação natural. Mas aqui surge outro problema:

Como saber qual socket e qual porta o sistema operacional usou exatamente na requisição que o APM diz ter demorado 10 segundos?

Você não sabe.
Seu monitoramento também não.
E essa correlação fina entre APM → SO → Rede simplesmente não existe.

Não é descuido.
É limitação técnica mesmo.

Monitoramos memórias, CPUs, discos, rede, GC, queries...
Mas quando precisamos rastrear uma única requisição por todas as camadas?

A observabilidade moderna não dá conta.

E isso é aceitável na maioria dos casos, pois geralmente o problema é grande o suficiente para aparecer em todas as métricas ao mesmo tempo.

Mas quando temos uma falha esporádica no meio de 1 milhão de requisições?

Aí começam os casos que podem levar meses para descobrir.
E na maioria das vezes, são ignorados, pois não geram um impacto critico.

Debug e Hands-on: indo para a lama

Voltamos à War Room.

O cliente abriu a VM → rodamos tcpdump.

Vimos algo mais ou menos assim e que já supeitavamos:

12:34:10.104512 IP 200.160.10.20.443 > 10.0.0.5.52144: Flags [S.], seq 987654321, ack 1234567891
12:34:10.410120 IP 200.160.10.20.443 > 10.0.0.5.52144: Flags [P.], seq 1:302, ack 517
12:34:10.411200 IP 200.160.10.20.443 > 10.0.0.5.52144: Flags [F.], seq 302, ack 518

12:34:11.022334 IP 200.160.10.20.443 > 10.0.0.5.52162: Flags [S.], seq 112233445, ack 765432101
12:34:11.260001 IP 200.160.10.20.443 > 10.0.0.5.52162: Flags [P.], seq 1:280, ack 498

12:34:11.909100 IP 200.160.10.20.443 > 10.0.0.5.52201: Flags [S.], seq 556677880, ack 443322111

Vamos entender esse exemplo de tcpdump:

12:34:10.104512 IP 200.160.10.20.443 > 10.0.0.5.52144: Flags [S.], seq 987654321, ack 1234567891
  • 12:34:10.104512 → Timestamp
  • IP → Indica que é um pacote IPv4 (o tcpdump mostraria "IP6" para IPv6).
  • 200.160.10.20.443 → Indica que o servidor do parceiro está respondendo, Ou seja: o servidor está enviando o pacote.
  • > → Direção do pacote, significa para.
  • 10.0.0.5.52144 → Endereço de destino + porta efêmera que o sistema operacional abriu para receber a resposta.
  • Flags [S.] → Flag do TCP para determinar o que significa o pacote

Perceba que o endereço de destino + porta efêmera muda constantemente, ou seja, muito provavelmente toda requisição abria um socket novo.

Rodamos netstat.

E a confirmação veio:

Mais de 1 mil sockets abertos, todos estavam em TIME_WAIT.

Quando vemos TIME_WAIT demais, significa:

  • A aplicação não está reutilizando conexões HTTP
  • Para cada chamada, ela abre um socket novo
  • Portanto, refaz handshake TCP
  • Portanto, paga latência extra
  • Portanto, aumenta a chance de pegar um momento ruim na rede ou no parceiro

Isso explica tudo?

Não necessariamente.
Mas é um dos fatores que contribui para uma lentidão intermitente.

Como resolver?

Simples (mas exige código):

  • Ativar HTTP keep-alive
  • Usar Session / Connection Pool
  • Manter o socket em estado ESTABLISHED

Assim a aplicação reaproveita conexões, evita bursts de DNS, reduz handshakes e estabiliza a latência.

Conclusão

No fim, parte do problema ainda pode estar do lado do parceiro.
Mas entregamos algo que muitas consultorias não entregam:

  • Teoria clara
  • Põe a teoria a prova (tcpdump, netstat, análise de sockets)
  • Explicação das limitações de APM e observabilidade
  • Evidências fortes para o cliente trabalhar com o parceiro
  • Melhorias concretas para aplicar no próprio código

O cliente entrou na War Room convencido de que o problema era do parceiro.
Saiu dela entendendo que parte da culpa também poderia ser dele e que seu APM, sozinho, não podia ser tratado como verdade absoluta.

E, sinceramente?
Para quem processa 1 milhão de requisições por dia, essa lição vale ouro.

Confira mais:

Fique por dentro das novidades

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