Blog/ Engenharia

WebSocket vs Polling

Polling parece simples, até você precisar de 12 camadas de métricas a cada 30 segundos em 150 servidores, e a matemática do request-per-second quebra rápido.

HS
Henrique Salles
CCS Team
07 · AGO · 2026

Quando começamos a desenhar o agente CCS, a primeira pergunta foi a mais óbvia: como o servidor manda dados pro painel? A resposta de instinto é “HTTP — POST a cada N segundos”. É o que todo mundo faz. É o que o Datadog Agent faz. É o que o Prometheus Node Exporter faz (com inversão, mas a ideia é a mesma).

Decidimos não fazer. Esta é a história do porquê.

POLLING HTTP: ~180 req/s em 150 servidores · 12 camadas · intervalo 10s

WEBSOCKET: 150 conn · conexões persistentes · streaming bidirecional

01 · Contexto

O agente CCS coleta 12 camadas de telemetria a cada 30 segundos: CPU, memória, disco, rede, Docker, processos, sessões SSH, segurança, logs, alertas, eventos do sistema, e snapshot de estado. Em uma frota média de 50 servidores, isso é volume considerável — não enorme, mas suficiente pra polling HTTP começar a doer.

Mas o motivo real não foi performance bruta. Foi latência bidirecional.

Polling diz “me dê o estado de agora.” WebSocket diz “me avise quando algo mudar.” É uma diferença de postura.

02 · A matemática que quebra

Faça o cálculo. 150 servidores, 12 camadas, intervalo de 10 segundos:

# polling HTTP
requests_per_second = 150 hosts × 12 layers / 10s
                     = 180 req/s

# cada request: TLS handshake (~3 RTTs), header, payload, fechar
overhead_per_req ≈ 600 bytes só de TLS + headers

# custo total de "ceremony" só pra abrir conexão
180 × 600 = 108 KB/s antes de transmitir 1 byte de métrica.

Isso ainda é gerenciável. O problema aparece quando você quer diminuir o intervalo. Polling a cada 1s? 1.800 req/s só pra atravessar a rede. Polling a cada 100ms (que é o que precisamos pra detectar SSH suspeito em tempo real)? 18.000 req/s. Em uma frota pequena.

A matemática quebra. E pior — quebra do lado errado: cresce com o tamanho da frota, não com a quantidade real de informação útil sendo trocada.

03 · Por que WebSocket

WebSocket inverte a equação. Você paga o custo de abrir conexão uma vez por servidor — não uma vez por coleta. A partir daí, é streaming bidirecional, full-duplex, sobre uma única conexão TCP persistente.

Decisão tomada: O agente CCS usa WebSocket binário com framing CBOR. Reconnect exponencial com jitter. Heartbeat a cada 15s. Buffer offline em SQLite local quando a conexão cai — sem perder métrica nenhuma na religação.

04 · Os trade-offs

WebSocket não é grátis. Algumas pegadinhas que tivemos que resolver:

Conexões persistentes saturam load balancer

O painel CCS termina WebSocket em um processo Rust dedicado (não Node, não Python). Cada conexão é uma task tokio — ~8KB de overhead. Saturamos 50k conexões em uma máquina de 4GB.

Proxy intermediário pode matar a conexão silenciosamente

Cloudflare desconecta WebSocket após 100s ocioso. Nginx default é 60s. Resolvemos com heartbeat ping/pong a cada 15s — se três pings caem, agente reconnect.

Debugging fica mais difícil

Não dá pra usar curl pra inspecionar. Construímos um ccs tail que abre uma conexão WebSocket e imprime o stream em tempo real. Custou uma semana. Vale ouro toda vez que precisamos.

05 · Os números

Depois de 6 meses rodando em produção em ~180 frotas de clientes, esses são os números reais:

06 · O que ficou

Se você está montando um sistema de telemetria pequeno (até 20 hosts) e tolerante a 1-2 minutos de latência, polling HTTP é defensável. É simples, fácil de debugar, qualquer proxy funciona.

Mas se você quer:

…então WebSocket vale o trabalho extra de robustecer. Pra nós, valeu.

O painel CCS é honesto sobre isso: o que você vê na tela existe porque um agente acabou de mandar. Não porque um cron job verificou às 14:30 e às 14:35 alguém vai conferir de novo.


— Henrique Salles · Eng · Plataforma · CCS