Loading...
Loading...
Bi-directional, full-duplex communication channels over a single persistent TCP connection.
HTTP polling vs WebSockets, load balancing, and Redis backplane.
Discover why HTTP Polling burns CPU, why WebSockets keep connections open, and how to safely scale state across multiple servers.
Persistent connections mean fewer new requests.
WebSockets keep connections open, so each connection uses server resources.
You already know from the HTTP module how every request pays headers plus a connection setup, and from the polling module how a fixed timer trades freshness against empty replies. Chat that asks the server every second sends ninety-nine empty what-is-new requests for one late message. A WebSocket, a single long-lived connection over which either side can send at any time after one HTTP-style handshake, holds one line open and lets the server speak the instant something happens: typing dots, live scores, shared cursors, all in milliseconds.
Think of a phone call versus mailing letters back and forth, the one comparison we will use here: letters pay postage and days per exchange while a call pays once to dial and then words flow freely either way. In the lab above, run 1,000 viewers polling every second versus holding 1,000 sockets and watch empty replies collapse into silence, because the line stays warm instead of redialing.
The naive client polls: open a connection, send headers, wait, close, repeat. We rejected shortening the poll interval as the fix because faster polling only multiplies the empty postage. Polling means asking on a timer whether anything is new. That is simple and stateless, and it charges full postage per ask while delaying news by up to one interval. The socket pays one handshake, upgrades the line (a protocol switch from request-reply to two-way frames, where a frame is one small wrapped message), and then each message costs a few bytes of framing. Work the overhead: 1,000 viewers polling every 2 seconds make 500 requests per second of mostly nothing, while 1,000 sockets make nearly zero requests until news exists.
The middle path is long-polling (holding one request open until news or timeout, then immediately reopening): fewer empties than polling, still one line per wait. It helps behind strict proxies but keeps the redial habit. In the lab, compare all three under 5,000 viewers and watch polling drown first, long-polling second, sockets last.
A socket pins its viewer to the box that answered: viewer A on box 1, viewer B on box 2. A chat message arriving at box 1 has no path to box 2 without help. The fix is a backplane (a shared channel every box publishes to and subscribes from, often Redis Pub/Sub, a simple broadcast feature of an in-memory store, or NATS, a lightweight message bus): box 1 publishes once, every box receives, each forwards to its own local viewers. Work the fan: 10 boxes times 10,000 viewers means one publish becomes 100,000 local sends, which is the intended multiplication. Without it the same setup delivers to 10,000 and silently drops the rest.
Two disciplines keep the line honest. Heartbeats (tiny ping-pong frames every 20 to 30 seconds) detect dead lines through proxies that silently drop idle connections, and reconnects with backoff (waiting 1s, then 2s, then 4s up to a cap, with jitter, meaning random spread) stop 100,000 viewers from redialing the same second after a blip. In the lab, add a second box without the shared channel and watch half the room miss the message, then enable the channel and watch delivery go whole, because publishing replaced hoping.
Bidirectional low-latency talk plus a shared channel fits rooms where everyone both speaks and listens. Try the lab with the balancer but no channel and watch messages stick to half the room, the exact failure this section exists to prevent.
SSE (server-sent events, a plain HTTP stream where the server pushes text lines and the browser resumes from the last id after drops) covers server-to-viewer-only flows with less machinery: it crosses proxies cleanly and replays from Last-Event-ID automatically. Pick it when viewers rarely speak back.
Rule of thumb: frequent server push in both directions calls for sockets plus a shared channel. Occasional one-way updates fit SSE or a patient long-poll. When 100,000 sockets each hold memory while mostly idling, how do you decide which connections deserve to stay open and which should have stayed polling?
Try this in the playground
Open a template and build it yourself — then take a quiz.