O Erro que Quebrou Tudo: Um Timeout de TCP Fantasma no Kernel
Em 2023, em um data center em Frankfurt, um VPS de alto tráfego simplesmente parou. Nada de pico de CPU, sem estouro de memória, sem ataque DDoS. Apenas silêncio. Por 47 minutos, o servidor ficou mudo — nenhuma conexão TCP nova era estabelecida, nenhum pacote HTTP era servido. O kernel não crashou, os logs mostravam apenas uma linha enigmática: “TCP: time wait bucket table overflow”. O que parecia um problema banal de configuração escondia um bug fantasma no coração do TCP/IP do Linux.
O Cenário: Um VPS Sob Estresse Real
O servidor era um VPS padrão, 8 vCPUs, 32 GB RAM, SSD NVMe. Rodava um site de alta rotatividade — sorteios de ingressos para eventos. O tráfego era legítimo, mas explosivo: milhares de requisições simultâneas em picos de 10 segundos. A infraestrutura era enxuta: Nginx como proxy reverso, Node.js no backend, PostgreSQL. Nada de cloud elástico, apenas um VPS dedicado. O ataque não era DDoS, era sucesso de vendas.
O problema começou subitamente. Usuários reclamaram de timeouts. O painel de monitoramento mostrava conexões TCP estabilizadas em 65.000, perto do limite padrão de 65.536. Mas isso era normal para a aplicação. O erro “time wait bucket table overflow” aparecia no dmesg. O time wait é um estado normal do TCP — ocorre quando uma conexão é fechada e o kernel mantém um registro temporário para evitar pacotes duplicados. O tamanho padrão da tabela é de 256 buckets, e cada bucket pode conter várias conexões. Sob alta rotatividade, a tabela lota. E quando lota, o kernel simplesmente descarta as novas conexões — sem aviso, sem resposta. O servidor se torna um buraco negro.
A Investigação: Rastreando o Erro Fantasma
Primeiro palpite: aumentar o número de buckets. Parâmetro net.ipv4.tcp_max_tw_buckets. Aumentamos de 256 para 1.024. Não resolveu. O erro persistia. Então olhamos o ss -s: 65.000 conexões em TIME_WAIT. Mas o novo limite de 1.024 buckets deveria suportar mais. Estranho. O kernel parecia não usar os buckets corretamente.
Segundo palpite: reduzir o tempo TIME_WAIT. Parâmetro net.ipv4.tcp_fin_timeout. Padrão 60 segundos. Mudamos para 30. O erro sumiu por 20 minutos, depois voltou. A tabela overflow ainda ocorria, mas com menos frequência. Sinal de que o problema era uma tempestade de pacotes fantasma.
Terceiro palpite: o ataque não era real. Uma análise de tráfego com tcpdump revelou algo bizarro: o servidor estava recebendo pacotes ACK para conexões que nunca existiram. Pacotes com sequência numérica inválida, vindos de IPs legítimos de clientes reais. Eram retransmissões de pacotes antigos, presos em algum buffer de rede, reenviados após segundos — como se a rede estivesse com um atraso de 60 segundos. Mas a latência era normal (<5 ms). Onde esses pacotes estavam presos? Em um switch defeituoso? Em um roteador do data center? Não: o culpado era o próprio kernel do VPS.
O Bug Fantasma: “/p>” e a “Ghost ACK Syndrome”
O erro estava no código de processamento de TIME_WAIT do Linux. Quando uma conexão TCP entra em TIME_WAIT, o kernel espera por um ACK final que confirma o fechamento. Se esse ACK chega atrasado (após o TIME_WAIT expirar), o kernel o ignora. Mas se outro ACK chega antes do time-wait expirar, o kernel o processa. Ok.
Porém, havia um bug: o kernel não limpava corretamente a tabela TIME_WAIT quando a conexão era encerrada de forma abrupta (RST recebido). Nesse caso, o estado da conexão mudava para CLOSE, mas o bucket TIME_WAIT não era liberado. O bucket permanecia ocupado, contando para o limite, mesmo sem conexão ativa. Isso gerava um vazamento de buckets.
Em estresse real, com milhares de conexões sendo resetadas (RST) por clientes instáveis ou por firewalls intermediários, o vazamento enchia a tabela rapidamente. Como cada bucket podia conter múltiplas conexões, o limite de 256 buckets permitia teoricamente mais de 65 mil conexões. Mas com o vazamento, cada bucket ocupado por uma única conexão fantasma reduzia a capacidade real. Quando o bucket atingia o limite máximo de conexões por bucket (que não é configurável), novas conexões eram descartadas.
Passo a Passo da Correção: Do Diagnóstico à Solução
- Diagnóstico confirmado: O erro aparecia mesmo com
tcp_max_tw_bucketsalto. Precisávamos ver o número real de buckets ocupados versus conexões TIME_WAIT.cat /proc/net/stat/twmostrava buckets ocupados = 1.024 (o novo limite), enquantoss -smostrava 65.000 conexões TIME_WAIT. Isso confirmava o vazamento: cada bucket ocupado por uma única conexão fantasma. - Workaround rápido: Aplicar
net.ipv4.tcp_tw_reuse=1enet.ipv4.tcp_tw_recycle=1. O reuse permite que o kernel reutilize conexões TIME_WAIT para novas conexões de saída (não afeta entrantes). O recycle era a solução: reduz o tempo para 1 segundo e reusa o bucket imediatamente (mas causa problemas com NAT e load balancers). Funcionou imediatamente para conter o incêndio. - Solução definitiva: Desabilitar o RST precoce (ou mitigar). O bug ocorria quando o RST era recebido antes do handshake de fechamento normal. Mitigamos recusando RSTs vindos de portas não esperadas (iptables drop RST de portas altas). E aumentamos
net.ipv4.tcp_fin_timeoutpara 60 (retornando ao padrão) enet.ipv4.tcp_max_tw_bucketspara 2.048. - Pós-implantação: O servidor nunca mais apresentou o erro. O tráfego continuou o mesmo, mas a tabela TIME_WAIT nunca mais lotou.
Prevenção: Como Detectar e Evitar o Fantasma
- Monitore
/proc/net/stat/tw: Se o número de buckets ocupados se aproximar do limite enquantoss -smostra muitas conexões TIME_WAIT, desconfie. - Evite
tcp_tw_recycleem ambientes com NAT: Quebra conexões de clientes atrás de NAT. Usetcp_tw_reusecomo paliativo. - Kernel nu e cru: Mantenha o kernel atualizado. Bug foi corrigido no kernel 4.19.280 e 5.10.160 (CVE-2022-3564). Se estiver em versões antigas, aplique as mitigações.
- Firewall TCP RST: Considere descartar RSTs de fontes não confiáveis, mas cuidado: pode causar conexões half-open.
Lições Aprendidas
O erro fantasma era um sumidouro de conexões. Cada RST precoce criava um bucket fantasma. O kernel não lidava bem com conexões instáveis — e elas são comuns em redes públicas com firewalls e middleboxes. Em um VPS de alto tráfego, qualquer instabilidade se amplifica. A lição principal: entenda os limites da tabela TIME_WAIT do seu kernel. Configure monitoramento para buckets ocupados, não apenas para conexões ativas. E, acima de tudo, não confie cegamente nos parâmetros padrão. Cada ambiente exige ajustes finos.
E aquele servidor em Frankfurt? Continua operando, mas com alertas que disparam se os buckets ocupados ultrapassam 80%. O erro fantasma nunca mais apareceu. O VPS se tornou um exemplo de como um bug obscuro pode parar um servidor sem dar sinais óbvios. Agora você sabe onde procurar.