WebSockets и SSE
1) Curto: o que e para quê
WebSocket (WS/WSS) é um upgrade de conexão HTTP para um canal todo duplex. Adequado para bate-papos, jogos ao vivo, colaborações, telemetria bidirecional.
Server-Sent Events (SSE) é uma linha unilateral de servidor para navegador (MIME 'text/event-stream'). Perfeito para tíqueres, notificações, cotações, progressos de tarefas. O cliente é 'EventSource'.
- É necessário digitar do cliente em tempo real (muitas vezes) → WebSocket.
- Apenas upgrade do servidor, compatibilidade e simplicidade é mais importante do que o SSE.
2) Rede e protocolos
2. 1 Transporte e compatibilidade
WebSocket: começa como HTTP 'GET... Upgrade: websocket` (HTTP/1. 1). O HTTP/2 pode ser RFC 8441 (CONNECT + ': protocol = websocket') e o suporte depende do proxy. Funciona sobre o TLS (WSS) - necessariamente em venda.
SSE: uma resposta HTTP de longa duração normal ('200 OK') com streaming. Vai perfeitamente através do HTTP/1. 1/2/3, compatível com CDN/proxy (a menos que os conectórios longos sejam furtados).
2. 2 Proxy/balanceadores/CDN
Verifique se o suporte de conexões de longa vida, caminhadas e temporizações, sessões de sticky (se o estado estiver no nó).
Para o WS: inclua 'proxy _ read _ timeout', 'upgrade' - cabeças, para-conexão de limite.
Para SSE: verifique se o proxy não está tampando a resposta (caso contrário, o cliente não verá os eventos a tempo).
3) Modelo de mensagens e controle de fluxo
WebSocket: quadros texto ou binários; há 'ping/pong', mas não há backpressure embutido - implemente no aplicativo (filas, janelas, drop-policy).
SSE: eventos de texto (UTF-8); O cliente, de forma integrada, sabe reconnect com atraso; o servidor pode definir 'retry:'. Há 'id:' e o título 'Last-Event-ID' para ser retomado da posição certa.
- Quente as mensagens de saída per-cliente.
- Limite a fila de eventos não assinados; Quando estiver cheio, afastar os de baixa prioridade/agregação.
- Para WS, use a janela deslizante e o padrão ACK ao nível do aplicativo.
4) Confiabilidade das conexões
4. 1 Detecção e keepalive
WS: envie 'ping' a cada N segundos; separação de tempo - reconnect com backoff exponencial + jitter.
SSE: o servidor envia «comentários» ':\n' como heartbeat para que a conexão não seja considerada idle; O cliente vai reencaminhar-se.
4. 2 Restauração de fluxo
WS: mantenha as mensagens offset/sequence e peça o delta após o recall.
Use 'id:' para cada evento e 'Last-Event-ID' na solicitação - o servidor envia os eventos omitidos.
5) Autenticação e autorização
JWT Bearer no URL de consulta (WS) não é seguro (vazamentos nos logs). Use o cabeçalho (através do handschake HTTP primário) ou cookies com as bandeiras «Secure», «HttpOnly», «SameSite».
É possível mTLS (especialmente para B2B) e assinaturas (HMAC) acima do pedido original.
Para SSE com cookies, lembre-se de KORS ('Access-Control-Allow-Origin', 'Allow-Credentals').
Rotação do token, não abram a borda. Passe «em breve» → o cliente reabre a conexão com o novo token.
6) Formato de dados e compressão
WebSocket: Ative o permessage-deflate com cuidado (CPU); evite compressões de formatos já comprimidos (Proto, Avro). Payload binário é mais econômico que JSON.
SSE: é texto; para grandes dados, envie um link para REST/gRPC recurso ou arquivos chunk; gzip de transporte para SSE - apropriado, mas acompanhe o tampão em proxy/CDN.
7) Escala e fã-out
7. 1 Escala Horizontal
Mantenha a aplicação sem projeto para reiniciar. Estado das conexões - na frente-camada; Os dados são do corretor.
O Sticky é necessário se houver filas locais.
O ideal é stateless front: o nó apenas multiplica as subscrições; os eventos vêm do pub/sub geral.
7. 2 Pub/Sub e corretores
Use Kafka/NATS/Redis Streams para obter um grande número de fãs.
A camada «Fanout Gateway» é assinada em topics e coloca os clientes em WS/SSE.
Use a chave de rotação (por exemplo, «userId», «matchId») para equilibrar a carga entre nodes.
8) Configs de produção
8. 1 NGINX — WebSocket
nginx map $http_upgrade $connection_upgrade { default upgrade; '' close; }
server {
listen 443 ssl http2;
server_name ws. example. com;
location /ws {
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_http_version 1. 1;
proxy_read_timeout 75s; # increase for long sessions proxy_send_timeout 15s;
proxy_pass http://ws-backend;
}
}
8. 2 NGINX - SSE (é importante desativar o tampão)
nginx location /events {
proxy_http_version 1. 1;
proxy_set_header Connection "";
proxy_buffering off; # is critical for proxy_cache off threads;
chunked_transfer_encoding on;
proxy_read_timeout 60m;
proxy_pass http://sse-backend;
}
8. 3 Kubernetes (Ingress Annotations, NGINX Ingress)
yaml metadata:
annotations:
nginx. ingress. kubernetes. io/proxy-read-timeout: "3600"
nginx. ingress. kubernetes. io/proxy-send-timeout: "3600"
nginx. ingress. kubernetes. io/enable-websocket: "true"
nginx. ingress. kubernetes. io/proxy-buffering: "off" # для SSE
9) Exemplos de código
9. 1 Cliente SSE (navegador)
js const es = new EventSource("/events? channel=odds", { withCredentials: true });
es. addEventListener("message", (e) => {
const data = JSON. parse(e. data);
renderOdds(data);
});
es. addEventListener("error", () => {
//EventSource will reconnect itself; can be shown spinner
});
9. 2 Servidor SSE (Node. js/Express)
js app. get('/events', (req, res) => {
res. writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
});
res. write ('retry: 3000\n\n') ;//3s backoff to client
const sub = subscribe(req. query. channel, (event) => {
res. write(`id: ${event. id}\n`);
res. write(`event: message\n`);
res. write(`data: ${JSON. stringify(event. payload)}\n\n`);
});
req. on('close', () => sub. unsubscribe());
});
9. 3 Cliente WebSocket (navegador)
js const ws = new WebSocket("wss://ws. example. com/ws");
ws. onopen = () => ws. send(JSON. stringify({ type: "join", room: "chat-1" }));
ws. onmessage = (m) => handle(JSON. parse(m. data));
ws. onclose = () => scheduleReconnect();
10) Segurança e restrição
Rate limiting per e per-usuário: limite a frequência de mensagens de entrada (WS) e a velocidade de fluxo de saída (WS/SSE).
Em termos de tempo de vida da conexão e tráfego total.
Message size limit и max messages/sec.
Filtros WAF/bot na fase de handschake; Proteção contra a conexão flooding (muitos conectórios curtos).
Isolamento de tenant/namespace: pool de recursos individuais.
11) Observabilidade
Métricas:- `connections_active`, `connections_new_total`, `bytes_in/out`,
- `messages_in/out_total`, `dropped_messages_total`,
- `reconnects_total`, `latency_delivery_ms{p50,p95,p99}`.
- Logi: IP/UA, userId/tenantId, motivo de encerramento ('close _ código'), duração.
- Tracing: vincule os eventos ao comando de origem (ID de correlação); para WS, use spans virtuais por batch.
12) Nuances operacionais
Terminação TLS mais próximo do cliente (CDN/edge).
Rotação de conexões (graceful) proativa durante os depósitos: dê a bandeira de volta.
Charding por chave para distribuir os canais quentes de forma uniforme.
Fotos de estado para seguidores recentes (snapshot + delta).
O último valor em dinheiro (SSE especialmente) é útil para o cliente «frio».
13) Anti-pattern
Estrim grandes fatias binárias via SSE ou JSON WS - Use o download HTTP e o link na mensagem.
Autorização somente no momento da conexão e ausência de inspeções de pena em sessões longas.
Sticky global sem necessidade → desequilíbrio e nódulos quentes.
Os temporizadores/limites desligados → os conectórios dependentes comem o pool.
O tampão SSE proxy/CDN → «tempo real» transforma-se em minutos de atraso.
Falta sequence/offset → após o reconnect, o cliente perde a integridade dos dados.
14) Folha de cheque de implementação
- O modelo selecionado é WS (bidirecional) ou SSE (unilateral).
- Os temporizadores, keepalive e reconnect (backoff + jitter) foram configurados.
- Foram projetados sequence/offset e (para SSE) 'id '/' Last-Event-ID'.
- Os limites definidos são tamanho/velocidade/conexões/quotas, proteção contra DoS.
- Config proxy/ingressa: upgrade, progy _ buffering off (SSE), read/send timeouts.
- Zoom: pub/sub-corretor, fã-out, sticky somente se necessário.
- Autenticação: transmissão segura de token, rotação sem penhasco.
- Observabilidade: métricas, logs, pistas; dashboards e alertas.
- Plano de lançamento: conexões graceful-drain, sinal ao cliente sobre conexão de pena.
- Game Days: falhas de rede, queda de buraco, superaquecimento do corretor, longas de RPT.
15) FAQ
A SSE pode ser armazenada com CDN?
Normalmente não, é um fluxo personalizado. Para canais públicos - talvez com um TTL curto e um chunked-delivery, mas fácil de introduzir «tempo real».
O WebSocket funciona sobre HTTP/2/3?
O WS de navegador começa com HTTP/1. 1-upgrade; há RFC 8441 para h2, suporte para proxy/servidor necessário separadamente. Com h3 - em movimento; para streaming em h3 tem WebTransport, mas é uma API diferente.
gRPC vs WS para o navegador?
Navegador limpo não diz gRPC; Precisamos de gRPC-Web através do Envoy. Para UI interativo, muitas vezes o WS + REST é mais fácil.
16) Resultados
WebSocket - quando é necessário um diálogo em tempo real e um canal bidirecional compacto.
SSE - quando você precisa de um push simples e confiável de servidor para cliente, complexidade mínima e reconnect automático.
Sucesso de venda são os horários e limites corretos, restauração com offset, pub/sub-fan-out, configurações de proxy corretas e observabilidade clara.