WebSockets и SSE
1) Breve: cosa e per cosa
WebSocket (WS/WSS) è un upgrade di connessione HTTP a un canale pieno-duplex. Adatto per chat, giochi live, collaudo, telemetria bidirezionale.
Server-Sent Events (SSE) - Strame unilaterale da server a browser (MIME 'text/event-stream'). Perfetto per i ticker, le notifiche, la quotazione, il progresso delle attività. Il cliente è «EventSource».
- È necessario immettere il cliente in tempo reale (spesso e molto) .
- Solo gli upgrade da server, compatibilità e semplicità sono più importanti di SSE.
2) Rete e protocolli
2. 1 Trasporti e compatibilità
WebSocket, inizia come HTTP 'GET... Upgrade: websocket` (HTTP/1. 1). Per HTTP/2 è possibile RFC 8441 (CONNECT + ': protocol = websocket'), il supporto dipende dal proxy. Funziona sopra TLS (WSS) - Obbligatorio in vendita.
SSE: normale risposta HTTP a lunga durata ('200 OK') con streaming. Va benissimo tramite HTTP/1. 1/2/3, compatibile con il CDN/proxy (a meno che non si avvolgano connettori lunghi).
2. 2 Proxy/bilanciatori/CDN
Controlla il supporto per connessioni a lunga vita, idoli e timeout, sessioni sticky (se lo stato è sul nodo).
Per WS, attivare «proxy _ read _ timeout», «upgrade» - zampe, per la connessione dei limiti.
Per SSE, assicurarsi che il proxy non buffi la risposta (altrimenti il client non vedrà gli eventi in tempo).
3) Modello di messaggi e controllo del flusso
WebSocket - fotogrammi di testo o binari c'è «ping/pong», ma nessun backpressure incorporato - implementare su un'applicazione (code, finestre, drop-policy).
SSE: eventi di testo (UTF-8) il client è integrato per il reconnect con ritardo il server può impostare «retry:». C'è «id:» e il titolo «Last-Event-ID» per riprendere dalla posizione desiderata.
- Quotare i messaggi per-client in uscita.
- Limitare la coda degli eventi non inseriti. In caso di sovraccarico, scartare le priorità basse/aggregare.
- Per WS, utilizzare la finestra di scorrimento e lo schema ACK a livello di applicazione.
4) Affidabilità delle connessioni
4. 1 Rilevamento e keepalive
WS: invia «ping» ogni n secondi; interruzione di timeout - reconnect con backoff esponenziale + jitter.
SSE: il server invia «commenti» come heartbeat in modo che la connessione non venga considerata idle; Il cliente si riconnetterà da solo.
4. 2 Ripristino del flusso
WS: mantieni i messaggi offset/sequence e richiedi il delta dopo il reconnect.
SSE: usa id: per ogni evento e Last-Event-ID nella query: il server invia gli eventi ignorati.
5) Autenticazione e autorizzazione
JWT Bearer nell'URL query (WS) non è sicuro. Usa il titolo (tramite l'handshake HTTP primario) o i cookie con le bandiere «Secure», «HttpOnly», «SameSite».
È possibile mTLS are (in particolare per B2B) e firmare (HMAC) sopra la richiesta iniziale.
Per SSE con cookie, ricordatevi di KORS ('Access-Control-Allow-Origin', 'Allow-Credentials').
Rotazione del token, non rovinate il buco. Passate «presto scaduto» al cliente di riaprire la connessione al nuovo token.
6) Formato dati e compressione
WebSocket: attivare il permessage-deflate con cautela (CPU) evitare la compressione di formati già compressi (Proto, Avro). Payload binario è più economico di JSON.
SSE: questo è testo; per i dati di grandi dimensioni, inviare un link alla risorsa o ai file chunk. gzip di trasporto per SSE - appropriato, ma tieni d'occhio il buffer in proxy/CDN.
7) Scalabilità e fan out
7. 1 Ridimensionamento orizzontale
Mantenere l'applicazione senza forma per il riavvio. Lo stato delle connessioni è nel fronte-livello. I dati sono del broker.
Sticky (hash per sessione/user) è necessario se ci sono code locali.
Ideale: fronte stateless: il nodo non fa altro che multiplicare le sottoscrizioni. gli eventi vengono dal pub/sub generale.
7. 2 Pub/Sub e broker
Utilizzare Kafka/NATS/Redis Streams per un grande fan-out.
Il livello «Fanout Gateway» si abbona ai topicini e allunga i clienti su WS/SSE.
Utilizzare la chiave di instradamento (ad esempio «userId», «matchId») per bilanciare il carico tra i nodi.
8) Configi di produzione
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 disattivare il buffer)
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) Esempi di codice
9. 1 Client SSE (browser)
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 Server 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 Client WebSocket (browser)
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) Sicurezza e limitazione
Rate limiting per connessione e per utente - Limitare la frequenza dei messaggi in ingresso (WS) e la velocità del flusso in uscita (WS/SSE).
Il tempo di vita della connessione e il traffico totale.
Message size limit и max messages/sec.
Filtri WAF/bot nella fase di handshake; Protezione contro la connection flooding (molti connettori brevi).
Isolamento da tenant/namespace: pool di risorse separati.
11) Osservabilità
Metriche:- `connections_active`, `connections_new_total`, `bytes_in/out`,
- `messages_in/out_total`, `dropped_messages_total`,
- `reconnects_total`, `latency_delivery_ms{p50,p95,p99}`.
- Loghi: IP/UA, userId/tenantId, motivo di chiusura ('close _ code'), durata.
- Tracing: collegare gli eventi al comando originale (ID correlati); Per WS, utilizzare span virtuali per batch.
12) Sfumature operative
Terminazione TLS più vicina al client (CDN/edge).
Rotazione proattiva delle connessioni (graceful) durante i depositi - Restituisci il flag di riconnessione.
Scharding su chiave per distribuire equamente i canali hot.
Istantanee di stato per follower recenti (snapshot + delta).
Cache ultimo valore (SSE in particolare) - Utile per il client freddo.
13) Anti-pattern
Strai pezzi binari di grandi dimensioni tramite SSE o JSON WS - Usa il download HTTP e il collegamento nel messaggio.
Autorizzazioni solo al momento della connessione e nessun controllo di penne durante lunghe sessioni.
Sticky globale senza bisogno di squilibri e nodi caldi.
Timeout/limiti disattivati, connettori dipendenti mangiano il pool.
Il buffer SSE proxy/CDN si trasforma in minuti di ritardo.
L'assenza di sequence/offset dopo il reconnect del client perde l'integrità dei dati.
14) Assegno foglio di implementazione
- Il modello selezionato è WS (bidirezionale) o SSE (unilaterale).
- Timeout, keepalive e reconnect configurati (backoff + jitter).
- Sono stati progettati sequence/offset e (per SSE) «id »/« Last-Event-ID».
- Limiti definiti: dimensioni/velocità/connessioni/quote, protezione da DoS.
- Config proxy/ingressa: upgrade, proxy _ buffering off (SSE), read/send timeouts.
- Scalabilità: pub/sub-broker, fan-out-gateway, sticky solo se necessario.
- Autenticazione: trasmissione sicura del token, rotazione senza dirupo.
- Osservabilità: metriche, fogli, piste; dashboard e alert.
- Piano di rilascio: connessioni graceful-drain, segnale al client di connessione penna.
- Game Days - Scollature della rete, caduta di nodi, sovraccarico del broker, lunghe RTT.
15) FAQ
È possibile memorizzare la cache SSE tramite CDN?
Di solito no, è un flusso personalizzato. Per i canali pubblici, è possibile avere TTL brevi e chunked-delivery, ma è facile inserire «tempo reale».
Il sistema funziona sopra HTTP/2/3?
Il browser WS inizia con HTTP/1. 1-upgrade; RFC 8441 per h2, supporto proxy/server richiesto separatamente. Con h3 - in movimento; per lo streaming nell'h3 c'è un WebTransport, ma questa è un'altra API.
gRPC vs WS per il browser?
Un browser pulito non dice gRPC; Ho bisogno di un contatto con Avvoy. Per le UI interattive è spesso più semplice WS + REST.
16) Riepilogo
WebSocket - quando è necessario un dialogo in tempo reale e un canale bidirezionale compatto.
SSE - Quando si desidera un push semplice e affidabile da server a client, la complessità minima e il reconnect automatico.
Il successo in vendita è il tempo e i limiti corretti, il ripristino offset, il pub/sub-fan-out, le impostazioni proxy corrette e la netta osservabilità.