Desenvolvimento de aplicações web em tempo real com websockets e server-sent events para experiências mais dinâmicas e escaláveis

Desenvolvimento de aplicações web em tempo real com websockets e server-sent events para experiências mais dinâmicas e escaláveis

Por que sua aplicação web precisa ser em tempo real (e o que isso significa na prática)

Hoje, se o seu app depende do usuário atualizar a página para ver algo novo, você já está ficando para trás. Chats, dashboards, notificações, sistemas de logística, plataformas de curso ao vivo, CRMs… tudo isso se beneficia de atualizações em tempo real.

Quando falo em “tempo real”, não é mágica. É basicamente: o servidor consegue enviar dados para o navegador assim que algo muda, sem o cliente ficar perguntando “e agora? já tem coisa nova?”. É aí que entram duas tecnologias que você precisa dominar:

WebSockets e Server-Sent Events (SSE).

Neste artigo, vou te mostrar:

  • Qual a diferença prática entre WebSockets e SSE
  • Quando usar cada um em projetos reais
  • Arquiteturas escaláveis para apps em tempo real
  • Um passo a passo simples para começar a implementar hoje
  • Checklist para não quebrar seu servidor em produção

WebSockets vs Server-Sent Events: o que muda de verdade

Vamos direto ao ponto. Os dois resolvem o mesmo tipo de problema: enviar atualizações do servidor para o cliente sem ficar fazendo polling (requisições repetidas a cada X segundos).

WebSockets

WebSocket é um protocolo que cria um canal de comunicação bidirecional entre cliente e servidor. Depois do handshake inicial (via HTTP), a conexão é “atualizada” para WebSocket e fica aberta.

O que isso significa?

  • Cliente pode enviar dados para o servidor a qualquer momento
  • Servidor pode enviar dados para o cliente a qualquer momento
  • Baixa latência (ótimo para apps interativos)

Casos típicos:

  • Chats e mensagens instantâneas
  • Multiplayer em jogos online
  • Aplicações colaborativas (Google Docs da vida)
  • Sistemas que exigem troca intensa de dados nos dois sentidos

Server-Sent Events (SSE)

Server-Sent Events usam um endpoint HTTP que mantém a conexão aberta e envia dados do servidor para o cliente em formato de stream. É uni-direcional: só o servidor envia eventos, o cliente apenas recebe.

No navegador, você usa a interface EventSource.

Características:

  • Somente servidor → cliente
  • Baseado em HTTP (mais simples de configurar em muitos backends)
  • Reconexão automática nativa pelo navegador
  • Formato de dados simples (texto, geralmente JSON)

Casos típicos:

  • Dashboards em tempo real (métricas, vendas, logs)
  • Notificações em tempo real
  • Streams de logs de servidor
  • Monitoramento de filas, jobs, processos longos

Resumo prático:

  • Se o cliente também precisa enviar mensagens em tempo real (chat, colaboração) → pense em WebSocket.
  • Se você precisa apenas empurrar atualizações do servidor para o cliente (dashboard, notificações) → SSE muitas vezes é mais simples.

Por que não usar só polling e pronto?

Polling (fazer requisições a cada X segundos) parece simples, mas escala mal.

Imagine:

  • 10.000 usuários conectados
  • Uma requisição a cada 5 segundos

Isso dá 2.000 requisições por segundo só para saber se “tem algo novo”. Em muitos cenários, 99% das respostas serão “nada mudou”. Você gasta banda, CPU e ainda gera latência desnecessária.

WebSockets e SSE evitam esse desperdício: a conexão fica aberta, o servidor só envia quando tem dado relevante.

Comparando WebSockets e SSE ponto a ponto

Para te ajudar a decidir, vamos olhar alguns critérios práticos.

1. Direção da comunicação

  • WebSocket: bidirecional (cliente ↔ servidor)
  • SSE: unidirecional (servidor → cliente)

2. Suporte de navegador

  • WebSocket: excelente suporte nos navegadores modernos
  • SSE: bom suporte na maioria dos navegadores modernos, mas histórico mais limitado em alguns contextos mobile e IE legado

3. Simplicidade de implementação

  • SSE: geralmente mais simples no backend (HTTP normal, sem necessidade de protocolo extra)
  • WebSocket: exige uma lib/protocolo específico, mas hoje frameworks já facilitam bastante

4. Escalabilidade

Ambos podem escalar bem, desde que você pense em:

  • Balanceadores de carga que suportem conexões persistentes
  • Um mecanismo de pub/sub (Redis, por exemplo) entre múltiplas instâncias de servidor

Na prática, o desafio não é só escolher a tecnologia, mas desenhar a arquitetura para suportar milhares de conexões simultâneas.

5. Recursos extras

  • SSE: reconexão automática embutida no EventSource, envio de último ID de evento
  • WebSocket: mais flexível para cenários complexos (salas, canais, protocolos customizados)

Arquiteturas reais para aplicações em tempo real

Vamos para o mundo real. Como isso fica numa arquitetura minimamente profissional?

Cenário 1: Dashboard em tempo real de vendas

Exemplo: você tem um e-commerce e quer mostrar em um painel as vendas acontecendo ao vivo para o time de marketing.

  • Quando uma venda é registrada na base, um evento é disparado
  • Um serviço de background publica esse evento em um canal Redis
  • Seu servidor HTTP (Node, Laravel, Django…) está inscrito nesse canal
  • Ao receber o evento, ele envia a atualização via SSE para todos os navegadores conectados

Por que SSE aqui?

  • O cliente só precisa receber dados
  • Você reaproveita o servidor HTTP tradicional
  • É fácil de debugar (stream de texto)

Cenário 2: Chat em tempo real entre usuários

Exemplo clássico: chat de suporte ou chat entre clientes.

  • Cada usuário abre uma conexão WebSocket
  • O servidor mantém um mapa de conexões por sala/usuário
  • Quando um usuário envia uma mensagem, o servidor recebe via WebSocket e já transmite para os destinatários conectados

Por que WebSocket aqui?

  • Cliente precisa enviar e receber mensagens o tempo todo
  • A bidirecionalidade reduz overhead
  • Libs como Socket.IO ajudam a lidar com salas, fallback, etc.

Um mini-guia prático: escolhendo entre WebSockets e SSE

Use como regra rápida:

  • Use SSE quando:
    • Você precisa só enviar atualizações do servidor para o cliente
    • Seu backend é muito acoplado a HTTP tradicional
    • Você quer algo simples para dashboards, notificações, logs
  • Use WebSocket quando:
    • Cliente precisa enviar dados constantemente
    • Você tem interação intensa (games, colaboração, chat)
    • Você planeja multiplexar canais/salas de comunicação

Se você ainda está em dúvida, pense assim:

“Meu usuário precisa falar muito com o servidor em tempo real, ou ele só precisa ouvir o que está acontecendo?”

Exemplo prático simples com Server-Sent Events

Vamos montar um exemplo conceitual de SSE. A ideia não é copiar e colar, mas entender o fluxo.

No backend (exemplo em Node/Express):

Você cria um endpoint /events que mantém a conexão aberta e envia eventos:

// Exemplo didático (omitindo imports e tratamento de erros)app.get('/events', (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); const sendEvent = (data) => { res.write(`data: ${JSON.stringify(data)}\n\n`); }; // Envia um "ping" inicial sendEvent({ message: 'conectado' }); // Exemplo: envia algo a cada 5s const interval = setInterval(() => { sendEvent({ timestamp: new Date().toISOString() }); }, 5000); req.on('close', () => { clearInterval(interval); });});

No frontend:

const source = new EventSource('/events');source.onmessage = (event) => { const data = JSON.parse(event.data); console.log('Novo evento:', data);};source.onerror = (err) => { console.error('Erro na conexão SSE', err);};

Com isso, você já tem um fluxo contínuo de dados do servidor para o cliente, sem precisar de WebSocket.

Exemplo prático simples com WebSockets

Agora, um fluxo didático usando WebSocket puro no navegador e um servidor simples.

No frontend:

const socket = new WebSocket('wss://seu-servidor.com/socket');socket.onopen = () => { console.log('Conectado!'); socket.send(JSON.stringify({ type: 'join', room: 'sala1' }));};socket.onmessage = (event) => { const data = JSON.parse(event.data); console.log('Mensagem recebida:', data);};socket.onerror = (err) => { console.error('Erro no WebSocket', err);};// Enviar mensagemfunction enviarMensagem(texto) { socket.send(JSON.stringify({ type: 'message', text: texto }));}

No backend, você usaria uma biblioteca específica dependendo da stack (por exemplo, ws em Node.js, canais em Rails, SignalR em .NET, etc.). O padrão é:

  • Aceitar nova conexão
  • Identificar o usuário/sala
  • Receber mensagens, processar e retransmitir para quem interessa

Cuidados para escalar aplicações em tempo real

É aqui que muitos projetos se complicam. Real time parece bonito no demo, mas o problema aparece quando você coloca 5.000 usuários simultâneos.

Alguns pontos essenciais:

1. Conexões persistentes custam memória

Cada conexão aberta ocupa recursos. Você precisa:

  • Configurar limites de conexões por servidor
  • Monitorar uso de memória e CPU
  • Avaliar se precisa de mais instâncias (horizontalizar)

2. Balanceadores de carga precisam saber lidar com isso

Se você usa Nginx, Cloudflare, ELB, etc., precisa garantir:

  • Suporte a keep-alive em HTTP para SSE
  • Suporte a upgrade de conexão para WebSocket
  • Sticky sessions (ou outra forma de roteamento consistente), se o estado da conexão estiver no servidor

3. Use um broker/pub-sub

Se você roda várias instâncias de backend, não dá para depender só de memória local. Use algo como:

  • Redis Pub/Sub
  • RabbitMQ
  • Kafka (para cenários mais pesados)

A ideia é simples: um serviço publica um evento (ex: “nova venda”), todas as instâncias inscritas recebem, e cada uma transmite para seus clientes conectados.

4. Timeouts e reconexões

  • Implemente lógica de reconexão no frontend (para WebSocket)
  • Para SSE, o navegador já tenta reconectar, mas você pode customizar
  • Tenha cuidado com loops de reconexão agressivos (efeito “DDoS de si mesmo”)

Checklist rápido antes de colocar em produção

Use esta lista como revisão final:

  • Você escolheu a tecnologia adequada ao fluxo do seu app (bidirecional ou só push)?
  • Seu balanceador de carga está configurado para conexões persistentes?
  • Você tem monitoramento de:
    • Quantidade de conexões ativas
    • Uso de memória e CPU
    • Latência média de envio de mensagens
  • Você implementou reconexão no cliente (para WebSocket)?
  • Você testou com usuários simulados (carga) antes de ir a público?
  • Há um mecanismo de autenticação e autorização nas conexões em tempo real?
  • Dados sensíveis não estão sendo enviados para quem não deveria receber?

Próximas ações para colocar tudo isso em prática

Para não ficar só na teoria, aqui vai um plano simples que você pode seguir em 1–2 dias de trabalho focado.

Passo 1: Escolha um caso de uso pequeno

  • Um contador em tempo real de usuários online
  • Um mini-dashboard com o número de pedidos do dia
  • Um chat interno simples entre admin e cliente

Passo 2: Defina se é caso de SSE ou WebSocket

  • Se for só exibir dados em tempo real (nada de o cliente mandar algo complexo) → teste SSE
  • Se tiver troca intensa (chat, colaboração) → vá de WebSocket

Passo 3: Implemente um protótipo

  • Crie um endpoint simples (SSE) ou um servidor de WebSocket
  • Implemente o frontend com uma UI mínima, mas funcional
  • Logue tudo no console para entender o fluxo (conectar, receber, desconectar)

Passo 4: Simule carga

  • Abra várias abas no navegador
  • Use scripts simples ou ferramentas como Artillery, k6, Locust
  • Veja onde o servidor começa a sofrer (e anote)

Passo 5: Ajuste arquitetura

  • Adicione cache/pub-sub (ex: Redis)
  • Otimize payloads (não envie JSON gigante sem necessidade)
  • Implemente logs e métricas específicas para o canal em tempo real

Desenvolver aplicações web em tempo real não é mais “luxo de big tech”. É algo acessível com ferramentas que você provavelmente já usa, como Node, PHP, Python, Redis, Nginx.

O diferencial não está só em saber “como fazer um WebSocket funcionar”, mas em escolher com consciência entre WebSockets e Server-Sent Events, e desenhar uma arquitetura que não quebre quando seu projeto começar a ganhar tração.

Se você já tem um projeto rodando hoje, o próximo passo é escolher um único ponto da sua aplicação para ficar em tempo real — e colocar em produção com cuidado. Depois disso, o resto vira evolução natural.