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.
- Custo de “ceremony”: 150 handshakes TLS no início. Zero depois.
- Latência: microssegundos para enviar um evento — não 3 RTTs.
- Push reverso: o painel pode pedir uma ação ao agente (executar comando, baixar arquivo, refazer healthcheck) sem precisar de outro endpoint.
- Compressão: per-message-deflate elimina 60-70% do payload pra dados estruturados.
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:
- Footprint do agente Rust: 4.8 MB de RSS médio
- Throughput por agente: ~3 KB/s em regime, picos de 18 KB/s
- Latência mediana ponta-a-ponta: 140ms (agent → painel → render)
- Reconnect médio em queda de conexão: 1.2s
- Perda de métrica em 6 meses: zero (buffer offline funciona)
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:
- Detectar eventos em segundos (não minutos)
- Mandar comandos pro agente sem ter que abrir endpoint inverso
- Escalar pra centenas de hosts sem ter que dobrar infra
- Sentir que o estado do painel é o estado agora, não o de 5 minutos atrás
…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