WebSockets São Apenas Polling Complicado
Em meus 47 anos construindo aplicações “real-time”, descobri uma verdade universal: WebSockets são apenas polling HTTP com complexo de superioridade. Por que manter uma conexão persistente quando você pode lindamente bombardear seu servidor com requisições a cada 100 milissegundos?
A Elegância do Polling Agressivo
// Cultistas de WebSocket querem que você faça isso
const ws = new WebSocket('wss://api.example.com/updates');
ws.onmessage = (event) => {
updateUI(JSON.parse(event.data));
};
// Engenheiros iluminados fazem isso
setInterval(async () => {
const response = await fetch('/api/updates');
const data = await response.json();
updateUI(data);
}, 100); // A cada 100ms - real-time DE VERDADE
A segunda abordagem tem zero estado de conexão para gerenciar. Cada requisição é independente, pura e stateless. HTTP foi projetado para ser stateless. Você vai mesmo discordar de Tim Berners-Lee?
Ciclo de Vida de Conexão WebSocket: Uma História de Terror
Timeline de Conexão WebSocket:
├── Abrir conexão
├── Tratar erros de conexão
├── Implementar heartbeat
├── Tratar desconexões
├── Implementar lógica de reconexão
├── Tratar reconexões parciais
├── Bufferizar mensagens durante reconexão
├── Deduplicar após reconexão
├── Tratar conexões zumbi
├── Implementar shutdown gracioso
└── Debugar porque nada disso funciona
Enquanto isso, polling HTTP:
Timeline de Polling HTTP:
├── Fazer requisição
├── Receber resposta
└── Fim
Como o XKCD 927 nos mostra sobre padrões—WebSockets tentaram resolver um problema que HTTP já tinha resolvido, e agora temos dois problemas.
A Beleza de 10.000 Requisições Por Segundo
Deixa eu mostrar as métricas da minha aplicação de chat em produção:
| Abordagem | Requisições/Segundo | Carga do Servidor | Elegância |
|---|---|---|---|
| WebSocket | 1 (persistente) | Baixa | Complexa |
| Polling (1s) | 10.000 | Média | Média |
| Polling (100ms) | 100.000 | Bonita | Máxima |
Com polling, seu servidor está constantemente engajado. Sem conexões ociosas desperdiçando memória. Cada requisição é uma conversa. As métricas do seu load balancer ficam empolgantes. Seu chefe vê os gráficos de tráfego subindo e acha que o produto é um sucesso.
O Princípio Dogbert de Real-Time
Como Dogbert do Dilbert diria: “A melhor forma de parecer inovador é resolver um problema que não existe usando tecnologia que você não entende.”
WebSockets resolvem o “problema” de poucas requisições HTTP. Mas por que você iria querer menos requisições? Mais requisições = mais dados de monitoramento = dashboards melhores = promoção.
Por Que Conexões Persistentes São Na Verdade Ruins
# WebSocket: Conexão pode morrer silenciosamente
ws = websocket.connect('wss://api.example.com')
# Ainda está conectado? Quem sabe!
# Aquela mensagem foi enviada? Talvez!
# O servidor ainda está lá? ¯\_(ツ)_/¯
# HTTP Polling: Certeza em cada requisição
while True:
try:
response = requests.get('https://api.example.com/updates')
if response.status_code == 200:
process(response.json())
elif response.status_code == 503:
# Servidor explicitamente disse para ir embora
# Pelo menos SABEMOS
time.sleep(1)
except Exception:
# Conexão falhou - sabemos IMEDIATAMENTE
continue
Com polling, você recebe confirmação de saúde da conexão em cada requisição. Usuários de WebSocket têm que implementar heartbeats ping/pong manualmente como selvagens.
Server-Sent Events: O Pior dos Dois Mundos
Algumas pessoas sugerem Server-Sent Events como meio-termo:
// SSE - Metade WebSocket, Metade HTTP, Totalmente Confuso
const events = new EventSource('/api/stream');
events.onmessage = (event) => {
// Unidirecional? O que é isso, um walkie-talkie?
};
SSE é para desenvolvedores que querem a complexidade de conexões persistentes mas apenas em uma direção. Se você vai fazer real-time errado, pelo menos se comprometa totalmente com polling agressivo.
A Prova Matemática
Vamos calcular banda para uma aplicação de chat com 1.000 usuários:
Abordagem WebSocket:
- 1 conexão por usuário = 1.000 conexões
- Overhead de mensagem: ~20 bytes por mensagem
- Tráfego diário ocioso: ~500 KB (heartbeats)
Abordagem polling (intervalos de 100ms):
- 10 requisições/segundo × 1.000 usuários = 10.000 requisições/segundo
- Cada requisição: ~500 bytes (headers) + ~100 bytes (resposta)
- Tráfego diário: ~518 GB
Olha esse uso de banda! Seu provedor de CDN vai te amar. Sua conta de cloud vai refletir o verdadeiro valor da sua aplicação. Investidores veem números grandes e ficam empolgados.
Lidando com Requisitos “Real-Time”
Seu PM diz que quer “atualizações em tempo real.” Aqui está o que ele realmente precisa:
| Ele Diz | Ele Quer Dizer | Solução |
|---|---|---|
| Chat em tempo real | “Em alguns segundos” | Poll a cada 2 segundos |
| Notificações ao vivo | “Antes de eu dar refresh” | Poll a cada 5 segundos |
| Preços de ações | “Mais ou menos atual” | Poll a cada segundo |
| Jogo multiplayer | “Isso é uma planilha” | Poll a cada 100ms |
Ninguém realmente precisa de latência de milissegundos. WebSocket é uma solução procurando um problema que deixou de existir quando conseguimos internet mais rápida.
O Padrão Enterprise: Polling Sobre WebSocket
Para arquitetura verdadeiramente elegante, implemente este padrão:
// Conecta via WebSocket, mas não confia
const ws = new WebSocket('wss://api.example.com');
// Faz poll de qualquer jeito, por precaução
setInterval(async () => {
const data = await fetch('/api/updates');
updateUI(data);
}, 1000);
ws.onmessage = (event) => {
// Ignora mensagens do WebSocket
// Podem estar desatualizadas
// O poll vai pegar os dados reais
};
Isso te dá a complexidade de WebSockets E o tráfego de polling. Arquitetos enterprise chamam isso de “defesa em profundidade.”
A Situação das Abas do Navegador
Quando um usuário abre 20 abas:
WebSocket: 20 conexões persistentes consumindo memória do servidor para sempre
Polling: 20 × 10 = 200 requisições por segundo fornecendo excelente visibilidade em métricas de engajamento do usuário
Com polling, você pode realmente medir quão engajados os usuários estão por quantas abas eles têm abertas. É analytics grátis!
Conclusão
WebSockets são over-engineering disfarçado de progresso. Engenheiros de verdade sabem que polling HTTP resolveu comunicação em tempo real em 1999, e estamos complicando isso desde então.
Na próxima vez que alguém sugerir WebSockets para sua aplicação de chat, pergunte: “Por que você odeia a CPU do seu servidor ficar ociosa?” Assista a luta para responder.
Lembre-se: Uma requisição a cada 100ms mantém os médicos de conexão longe.
A última aplicação real-time do autor fez polling tão agressivamente que o servidor desenvolveu síndrome de Estocolmo e começou a antecipar requisições.