All Posts

Real-Time Communication: WebSockets, SSE, and Long Polling Explained

When to use WebSockets vs Server-Sent Events vs Long Polling โ€” with real production examples.

Abstract AlgorithmsAbstract Algorithms
ยทยท23 min read
Share
Share on X / Twitter
Share on LinkedIn
Copy link

TLDR: ๐Ÿ”Œ WebSockets = bidirectional persistent channel โ€” use for chat, gaming, collaborative editing. SSE = one-way server push over HTTP with built-in reconnect โ€” use for AI streaming, live logs, notifications. Long Polling = held HTTP requests โ€” the pragmatic fallback when WebSockets are blocked. Short Polling = simplest but most wasteful โ€” only for low-frequency, low-traffic scenarios. The decisive question is always: does the client need to send data back in real time?


๐Ÿ“– The Problem HTTP Was Never Designed to Solve

When you type a message in Slack and it appears instantly on your colleague's screen in Tokyo, that's not magic โ€” it's a persistent WebSocket connection that stays open between your browser and Slack's servers. But when you check Twitter's notification bell, it doesn't use WebSockets โ€” it uses Long Polling. And ChatGPT's streaming responses use a third approach entirely: Server-Sent Events. Why do three similar "show me new data" problems get three different solutions?

The root cause is HTTP's fundamental design. HTTP is a request-response protocol: the client asks, the server answers, the connection closes. The server has no way to push data to the client unprompted. Every piece of data you see on a webpage started with your browser explicitly asking for it.

This worked fine for 1990s web pages. Modern applications need the opposite: server-initiated events. Your Slack client needs to know when a message arrives โ€” without constantly asking "anything new?"

The naive fix is to poll the server on a timer. At 1 million users polling every second, you generate 1 million HTTP requests per second. At roughly 1 KB per request and response, that's 1 GB/s of bandwidth โ€” 99% of which returns an empty "nothing new" response. The polling tax compounds with scale.

Real-time communication patterns are engineering solutions to this HTTP limitation, each trading off latency, connection overhead, infrastructure complexity, and directionality in different ways.


๐Ÿ” Four Approaches to Real-Time Data: An Overview

All four patterns solve the same problem โ€” getting fresh data from server to client โ€” but they differ along two critical axes: how long the connection stays open and whether the client can also send data.

PatternConnection LifetimeDirectionRelative LatencyRelative Server Overhead
Short PollingNew request each intervalClient โ†’ Server โ†’ ClientHigh (interval delay)High (requests/sec)
Long PollingHeld open until data arrivesClient โ†’ Server โ†’ ClientLow (~100 ms)Moderate (held connections)
Server-Sent Events (SSE)Single stream, kept openServer โ†’ Client onlyVery low (~50 ms)Low (open streams)
WebSocketsPersistent after upgradeBidirectionalExcellent (~20 ms)Low per message; high at scale

The right choice depends not just on latency needs but on infrastructure reality: corporate proxies, CDNs, and load balancers often make WebSockets harder to deploy than their latency profile would suggest.


โš™๏ธ How Each Pattern Delivers Data in Practice

Short Polling: The Simplest Approach That Doesn't Scale

Short Polling is the default mental model for most engineers: the client sends a regular HTTP GET on a timer and immediately receives whatever data is available โ€” including an empty response when there's nothing new.

GET /api/notifications HTTP/1.1
โ†’  {"events": []}               โ† 99% of the time
โ†’  {"events": [{"id": 42}]}     โ† occasionally

The appeal is simplicity: any HTTP server handles it, no special infrastructure, easy to debug. It works acceptably for truly infrequent updates (status checks every 30 seconds, config polling) with small user counts. Every request carries full HTTP headers (~500 bytes), opens a connection, completes a TLS handshake, and tears down โ€” even when returning nothing. At 100,000 users polling every 2 seconds, that's 50,000 requests/second for a feature that's idle most of the day.

Long Polling: Holding the Line Until There's News

Long Polling improves on Short Polling by holding the HTTP request open on the server until data becomes available. The server responds only when it has something to say.

Client: GET /api/events        โ†’ (server holds the HTTP response object)
                               โ†’ (20 seconds pass, nothing happens)
Server:                        โ†’ 200 OK {"event": "new_message", "id": 7}
Client: GET /api/events        โ†’ (immediately re-opens the request)

This is called the Hanging GET pattern. The client immediately re-sends the request after receiving a response, maintaining near-continuous server coverage. A message published server-side reaches the client in ~50โ€“100 ms (network RTT), not after a full polling interval. Twitter used Long Polling for notification dots and timeline updates for years โ€” sub-second delivery without the complexity of WebSockets.

The limitation: each held-open request occupies a file descriptor and memory on the server. At 500,000 concurrent users, that's 500,000 open connections. Async I/O runtimes (Node.js, Netty) handle this efficiently, but stateful load balancers and proxies sometimes close "idle" connections prematurely, triggering immediate reconnect storms.

Server-Sent Events: A Persistent One-Way HTTP Stream

Server-Sent Events establish a single long-lived HTTP response over which the server continuously streams events. Unlike Long Polling, the connection stays open indefinitely โ€” the server keeps writing to it.

GET /stream HTTP/1.1
Accept: text/event-stream

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache

data: {"type":"notification","id":1}

event: heartbeat
data: ping

data: {"type":"message","id":2}

The browser-side EventSource API makes this remarkably simple to consume:

const es = new EventSource('/stream');
es.onmessage = (e) => console.log(JSON.parse(e.data));
es.addEventListener('heartbeat', () => console.log('alive'));
// EventSource automatically reconnects on disconnect โ€” no manual retry logic needed
// On reconnect, the browser sends Last-Event-ID so the server can replay missed events

SSE's built-in reconnection is its most underrated feature. When a mobile network drops, EventSource automatically retries and includes Last-Event-ID, allowing the server to replay any events the client missed โ€” at-least-once delivery semantics with zero application code. ChatGPT uses SSE to stream generated tokens to your browser as the model produces them. GitHub Actions uses it to stream live build logs line by line.

The hard constraint: SSE is strictly one-directional โ€” server to client only. The client cannot send data back over the SSE channel. For scenarios where the client also needs to push (chat, live editing), a separate HTTP request or a different pattern is required.

WebSockets: Full-Duplex Over a Persistent TCP Channel

WebSockets begin as an ordinary HTTP request but immediately negotiate an upgrade to a raw TCP channel:

GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

After the 101 response, HTTP is gone. The TCP connection carries framed messages in both directions simultaneously. Either side can write at any time โ€” no polling, no request overhead, no half-duplex constraint. A WebSocket frame for a small message (< 126 bytes) carries only 2 bytes of framing overhead, compared to 500+ bytes of HTTP headers for the equivalent polling request.

Slack keeps one WebSocket connection open per active browser tab. Typing a message sends a text frame directly to the server. A reply from Tokyo arrives as an incoming frame without any client-side request. Figma synchronizes cursor positions across all participants using WebSocket binary frames โ€” each mouse movement generates a ~20-byte frame fanned out to every connected client in the same document.


๐Ÿง  Deep Dive: Connection State, Internals, and Protocol Costs

The Internals: What the Server Actually Holds

Each pattern has a fundamentally different server-side resource profile, and choosing the wrong one for your scale can break production.

Short Polling is stateless. Each request is independent. Any HTTP server handles it natively โ€” no persistent state, no special infrastructure. The cost is pure throughput: CPU, bandwidth, and request-handling capacity consumed proportionally to polling frequency.

Long Polling requires the server to hold the HTTP response object in memory for each waiting client. In Node.js, a held response is just a deferred callback on the event loop โ€” lightweight. In thread-per-request frameworks (early Java Servlet containers), each held connection occupies a thread. At 100,000 concurrent users, that's 100,000 blocked threads โ€” a deployment that needs async I/O or you'll run out of threads before you run out of memory.

SSE holds a single HTTP response stream per client. The server calls response.write() whenever a new event is ready. The connection object lives in application memory for the session lifetime. HTTP/2 SSE is especially efficient: multiple streams multiplex over a shared TCP connection. Most browser EventSource implementations default to HTTP/1.1, where each SSE stream occupies one of the browser's 6 per-domain connections โ€” a real constraint to watch for.

WebSockets hold a raw TCP socket per client, managed outside the normal HTTP request lifecycle. At 1 million concurrent connections you need roughly:

  • 1 GB RAM minimum (1 KB per socket ร— 1 M sockets) just for socket state
  • A message broker (Redis pub/sub or Kafka) to fan out messages across server instances โ€” a WebSocket connection is pinned to the server that accepted it
  • Sticky sessions or a connection router so outbound messages reach the correct server

Performance Analysis: Overhead per Delivered Message

MetricShort PollingLong PollingSSEWebSockets
Header overhead per event~500 bytes~500 bytes~20 bytes2โ€“14 bytes
TCP handshakeEvery requestPer reconnectOnce per sessionOnce per session
Effective latencyInterval-length~50โ€“200 ms~30โ€“100 ms~10โ€“50 ms
Memory: 1 M concurrent usersStateless~500 MB~200 MB~1 GB
Fan-out complexityNone (stateless)ModerateModerateHigh (requires broker)

WebSockets dominate on raw latency and per-message bandwidth. Short Polling is the worst performer at scale. SSE occupies a well-balanced middle ground for one-directional workloads โ€” nearly as efficient as WebSockets per event, with dramatically simpler server infrastructure and no need for a message broker.

The practical trade-off: WebSockets are best when you need bidirectionality and can absorb the scaling infrastructure cost. For everything else, SSE is almost always the more economical choice.


๐Ÿ“Š Connection Lifecycle: Seeing All Four Patterns Side by Side

graph LR
  subgraph SP["โ‘  Short Polling"]
    C1[Client] -->|GET every N seconds| S1[Server]
    S1 -->|Instant response โ€” empty or data| C1
  end

  subgraph LP["โ‘ก Long Polling"]
    C2[Client] -->|GET /updates| S2[Server]
    S2 -->|Held open โ€” responds only when data ready| C2
  end

  subgraph SSE_["โ‘ข Server-Sent Events"]
    C3[Client] -->|GET /stream Accept: text/event-stream| S3[Server]
    S3 -->|Persistent stream โ€” server writes events continuously| C3
  end

  subgraph WS_["โ‘ฃ WebSockets"]
    C4[Client] -->|HTTP GET + Upgrade: websocket| S4[Server]
    S4 -->|101 Switching Protocols| C4
    C4 <-->|Full-duplex framed messages โ€” either side writes any time| S4
  end

Reading the diagram: Short Polling and Long Polling both use repeated HTTP requests โ€” the only difference is how long the server waits before responding. SSE opens a single HTTP stream that the server continuously writes to, with the client as a passive reader. WebSockets are the only pattern where the client and server each hold a write handle simultaneously โ€” the bidirectional arrow is the defining architectural distinction.

Why connection lifetime matters: Every new HTTP connection pays a TCP + TLS handshake cost (~3 round trips for TLS 1.3). Short Polling pays this on every interval. Long Polling pays it on every event delivery (reconnect after response). SSE and WebSockets pay it exactly once per session, then amortize that cost across all subsequent messages.


๐ŸŒ Real-World Applications: Who Uses WebSockets, SSE, and Long Polling in Production

Slack โ†’ WebSockets. Every active Slack session maintains a persistent WebSocket. Messages, typing indicators, read receipts, and presence heartbeats all transit the same channel. Slack's backend routes WebSocket frames through a Redis pub/sub layer so that when Alice's message arrives on Server A, it fans out to Bob's connection on Server B. The bidirectionality of WebSockets is essential โ€” the client sends typing events and ACKs back to the server over the same connection.

ChatGPT โ†’ Server-Sent Events. GPT-4's output is generated token-by-token. OpenAI streams each token as an SSE event the moment the model produces it. The "typing" effect you see in the interface is real โ€” tokens are generated sequentially and delivered via SSE with ~50 ms latency per batch. SSE is the correct choice here because communication is one-way only: the server streams, the client displays. The initial prompt was already sent via a regular HTTP POST.

Twitter (historically) โ†’ Long Polling. Twitter's notification bell and real-time timeline used Long Polling for years. Their engineering team documented that WebSockets added sticky session and fan-out complexity that was disproportionate to their primarily-read workload โ€” notifications flow from server to client, and sub-second delivery was achievable without a persistent bidirectional channel.

GitHub Actions โ†’ Server-Sent Events. Live build logs stream to your browser as each pipeline step executes. The server appends log lines to an SSE stream in sequence. If your network drops mid-build, Last-Event-ID lets the browser resume the stream from the last received line โ€” no missed log output and no full-page reload.

Online multiplayer games โ†’ WebSockets. Agar.io, Slither.io, and similar browser games use WebSockets for bidirectional position sync at 20โ€“60 messages/second per player. At this frequency, the 2-byte WebSocket frame header is critical โ€” an equivalent polling approach would spend more bandwidth on HTTP headers than on the actual game state.


โš–๏ธ Trade-offs & Failure Modes: Why Each Real-Time Pattern Has a Price

DimensionShort PollingLong PollingSSEWebSockets
Delivery latencyHigh โ€” interval delayLow โ€” ~100 msVery low โ€” ~50 msExcellent โ€” ~20 ms
Bandwidth efficiencyPoor โ€” full headers per pollModerate โ€” headers per eventHigh โ€” framing onlyHighest โ€” 2-byte frames
Server stateNone (stateless)Held response objectsHeld stream objectsRaw TCP sockets
Bidirectional?NoNoNoYes
Auto-reconnectClient implementsClient must re-pollBuilt-in (EventSource)Manual or library
Proxy/firewall compatibilityExcellentGoodGoodVariable โ€” often blocked
Scaling infrastructureNone neededAsync serverAsync serverBroker + sticky sessions
HTTP/2 benefitMultiplexingMultiplexingMultiplexing + stream reuseNot applicable (upgrades away from HTTP)

Failure modes to plan for:

WebSocket connection loss at scale. Mobile networks and corporate proxies aggressively terminate connections that appear idle. Without server-to-client heartbeat pings every 25โ€“30 seconds, clients silently disconnect while the server still believes the connection is alive. Implement ping/pong and exponential-backoff reconnect on every WebSocket deployment.

Long Polling timeout storms. If your server imposes a 30-second hold timeout and 100,000 clients all hit it simultaneously (e.g., after a server restart), you receive a 100,000-request wave the instant the timeout expires. Jitter individual timeouts by ยฑ5โ€“10 seconds to spread the reconnect load.

SSE and the HTTP/1.1 browser connection limit. Browsers cap HTTP/1.1 connections per origin at 6. If you open six SSE streams from a single tab (or a single page uses multiple SSE-backed widgets), you exhaust the limit and subsequent requests queue. The fix is HTTP/2 (which multiplexes over one TCP connection with no per-stream limit) or consolidating all server events into a single SSE endpoint filtered by topic.

WebSocket fan-out across instances. A WebSocket connection is pinned to the server instance that accepted the upgrade. When you scale horizontally, a message arriving at Instance A must reach users connected to Instance B, C, and D. The standard solution is a Redis pub/sub topic or Kafka partition that every instance subscribes to โ€” but this pub/sub layer becomes a throughput bottleneck under heavy fan-out.


๐Ÿงญ Decision Guide: Choosing the Right Real-Time Protocol

graph TD
    A{Is real-time\ncommunication\nbidirectional?} -->|Yes| WS["WebSockets\nSlack ยท Figma ยท Google Docs\nLive trading ยท Games"]
    A -->|No โ€” server push only| B{Can you use\nlong-lived HTTP?}
    B -->|"Yes (most environments)"| C{How frequent\nare updates?}
    B -->|"No โ€” proxy or CDN blocks it"| LP["Long Polling\nTwitter-style notifications\nLegacy proxy environments"]
    C -->|High or continuous stream| SSE["Server-Sent Events\nChatGPT ยท GitHub Actions\nStock tickers ยท Notifications"]
    C -->|Low โ€” minutes apart| D{User scale?}
    D -->|"Small (< 10,000 users)"| SP["Short Polling\nAdmin dashboards\nStatus checks"]
    D -->|"Large (> 10,000 users)"| LP2["Long Polling\nNotification dots\nEmail clients"]

Start at the bidirectional question every time. Engineers frequently reach for WebSockets by default, but WebSockets add broker infrastructure, sticky session requirements, and reconnect management that SSE or Long Polling handle more simply for unidirectional workloads.

Use WhenRecommended Pattern
Chat, multiplayer games, collaborative editingWebSockets
AI token streaming, live build logs, push notificationsServer-Sent Events
Notification dots, timeline updates, enterprise firewall environmentsLong Polling
Config checks, status polling with < 10,000 usersShort Polling
Updates are strictly server-to-clientSSE preferred over WebSockets
Corporate proxies or CDNs block persistent connectionsLong Polling as fallback
You need client-initiated messages at high frequencyWebSockets

๐Ÿ› ๏ธ Socket.IO: Intelligent Fallback for Any Environment

Socket.IO is the most widely used real-time library for Node.js. Its core value is automatic transport negotiation: it attempts a WebSocket upgrade first, falls back to HTTP Long Polling if WebSockets are blocked (by a proxy or CDN), and degrades further if needed โ€” transparently, without any application code change. This makes it the pragmatic choice for public-facing applications where you cannot control every client network environment.

Socket.IO also layers on rooms (named broadcast groups), namespaces (logical sub-connections), built-in exponential-backoff reconnect, and acknowledgment callbacks โ€” infrastructure you would otherwise write yourself.

// Server โ€” Node.js + Socket.IO
import { createServer } from 'http';
import { Server } from 'socket.io';

const httpServer = createServer();
const io = new Server(httpServer, {
  transports: ['websocket', 'polling'], // try WebSocket first; fall back to Long Polling
  pingInterval: 25_000,                 // heartbeat ping every 25 seconds
  pingTimeout:  20_000,                 // close if no pong within 20 seconds
  cors: { origin: 'https://your-app.com' },
});

io.on('connection', (socket) => {
  socket.join('room:project-42');                     // subscribe socket to a named room
  socket.on('message', (msg) => {
    io.to('room:project-42').emit('message', msg);    // broadcast to everyone in the room
  });
  socket.on('disconnect', () => console.log('user left'));
});

httpServer.listen(3000);
// Client โ€” browser
import { io } from 'socket.io-client';

const socket = io('https://your-server.com');   // auto-negotiates best transport
socket.on('message', (msg) => renderMessage(msg));
socket.emit('message', { text: 'Hello from client' });

Scaling Socket.IO beyond one server requires the @socket.io/redis-adapter, which uses Redis pub/sub to relay events across instances. Without it, a message emitted on Instance A never reaches clients connected to Instance B. The same fan-out problem applies to raw WebSockets โ€” Socket.IO just makes the adapter integration one npm install away.

For a full treatment of Socket.IO's clustering model and Redis adapter configuration, see the official Socket.IO multi-node documentation.


๐Ÿงช Designing a Live Notification System

Scenario: A project management tool (similar to Linear or Jira) needs to deliver real-time notifications to users when a task is assigned, a comment is posted, or a sprint is kicked off.

Traffic profile: 200,000 active users, averaging 5 notifications per user per hour, with bursts of 10,000 notifications in 10 seconds when a sprint launches.

Pattern Selection Walkthrough

Decision PointAnswerImplication
Bidirectional communication?No โ€” server pushes to browserEliminates the WebSocket mandate
Update frequency?Low on average; burst-ableSSE handles bursts without reconnect storms
Reconnect behavior needed?Yes โ€” mobile clients drop constantlySSE's built-in Last-Event-ID replay handles this
Infrastructure available?HTTP/2 load balancer (AWS ALB v2)SSE streams multiplex over shared TCP; no per-stream limit
WebSockets blocked by proxies?Some enterprise users affectedSSE is HTTP โ€” passes through all standard proxies

Verdict: Server-Sent Events. Each authenticated user opens one EventSource('/api/notifications/stream') connection. The backend publishes a notification event whenever one is triggered. On mobile reconnect, the browser automatically retries with Last-Event-ID, and the server replays any events the client missed.

What the backend holds: At 200,000 open SSE streams, the server holds approximately 400 MB of active HTTP response stream objects โ€” well within budget for a service of this profile. No message broker fan-out is needed if notifications are user-specific (each user has their own stream); a simple in-memory pub/sub per user-id is sufficient.

Why not WebSockets? The communication is strictly one-way โ€” the browser never needs to push notification data back to the server. Using WebSockets would require sticky sessions, a Redis adapter for fan-out, and reconnect handling logic โ€” all for zero functional gain over SSE on this workload.

Why not Long Polling? SSE's persistent stream is more efficient than repeatedly reconnecting Long Polling connections, especially during the 10,000-notification burst. A burst triggers 10,000 Long Polling responses in 10 seconds, causing 10,000 immediate reconnect requests. SSE delivers the same 10,000 events as writes to open streams โ€” no reconnect wave.


๐Ÿ“š Lessons Learned from Real Production Systems

Don't reach for WebSockets by default. The most common mistake is defaulting to WebSockets because they feel "more real-time." WebSockets are the right tool for bidirectional workloads. For one-way server push, SSE is almost always the more operationally simple and cost-effective choice โ€” fewer moving parts, no broker dependency, and automatic reconnect built in.

Corporate proxies break WebSockets more often than engineers expect. HTTP CONNECT proxies, layer-7 load balancers, and enterprise firewalls routinely reject or timeout WebSocket upgrade requests. Always design a fallback (Socket.IO's transport negotiation exists precisely because this is a pervasive real-world problem, not a theoretical edge case).

Heartbeats are non-negotiable for any persistent connection. Without server-to-client pings every 25โ€“30 seconds, network middleboxes silently kill "idle" connections after 60โ€“300 seconds. The server's connection map diverges from reality โ€” it believes 200,000 clients are connected while the actual number is far lower. Measure active vs. registered connections continuously.

SSE's Last-Event-ID is free at-least-once delivery โ€” use it. Many teams implement SSE without event IDs and only discover the gap when mobile users report missed notifications after a network transition. Assigning a monotonically increasing ID to every event and replaying from Last-Event-ID on reconnect costs almost nothing server-side and eliminates a whole class of production bugs.

Model the fan-out math before you scale WebSockets. A single Redis pub/sub topic delivering to 1 million subscribers generates roughly 1 million network writes per message published. At 100 messages/second, that's 100 million writes/second โ€” well beyond a single Redis instance. Partition by topic, room, or user cohort before you hit this wall, not after.


๐Ÿ“Œ TLDR: Summary & Key Takeaways

  • Short Polling is simple and stateless but wastes bandwidth proportionally to user count โ€” viable only for low-frequency, small-scale polling scenarios.
  • Long Polling achieves near-real-time delivery over standard HTTP with no special protocol โ€” the pragmatic fallback when WebSockets are blocked by infrastructure.
  • SSE offers one-way server push with automatic reconnect and Last-Event-ID replay baked in โ€” the best default for notifications, AI token streaming, and live logs.
  • WebSockets provide full-duplex bidirectional real-time communication at minimal per-message overhead โ€” essential for chat, collaborative editing, gaming, and live trading.
  • The bidirectionality question drives the primary decision: if the client never needs to push data back in real time, SSE is almost always simpler and cheaper than WebSockets.
  • Socket.IO adds transport fallback, rooms, and built-in reconnect โ€” production-ready scaffolding for Node.js real-time apps, with Redis adapter for horizontal scale.
  • Scaling WebSockets requires a message broker for fan-out, sticky sessions or a routing layer, and careful heartbeat management โ€” plan this architecture before you need it.

The one-liner: Use SSE when the server talks, WebSockets when both sides talk, Long Polling when infrastructure gets in the way, and Short Polling only when immediacy doesn't matter.


๐Ÿ“ Practice Quiz

  1. Your team is building an AI assistant that streams generated text token-by-token from server to browser. The client only sends prompts via a regular HTTP POST. Which transport should handle the streaming response?

    • A) WebSockets โ€” bidirectional, so the browser can cancel mid-stream
    • B) Server-Sent Events โ€” one-way server push with built-in reconnect and no extra infrastructure
    • C) Long Polling โ€” simpler to implement and sufficient for token-by-token delivery Correct Answer: B
  2. A multiplayer browser game needs to sync player positions between all connected clients at 30 updates per second. Each position update is ~50 bytes. The client must both send its own position and receive all other players' positions. Which pattern is most appropriate?

    • A) Server-Sent Events with a separate HTTP POST for each position update from the client
    • B) Long Polling โ€” sufficient for 30 updates/second with manageable reconnect overhead
    • C) WebSockets โ€” bidirectional, persistent, with 2-byte frame overhead versus 500+ bytes per HTTP request Correct Answer: C
  3. You deploy a WebSocket service with 4 horizontally scaled instances behind a load balancer. User Alice is connected to Instance A. User Bob is connected to Instance B. Alice sends a message to Bob. What happens without additional infrastructure, and what is the standard fix?

    • A) The load balancer automatically routes the frame to Bob's instance โ€” no fix needed
    • B) Bob never receives the message; fix with a Redis pub/sub broker that all instances subscribe to
    • C) Alice's message is queued in a database and Bob polls for it on next heartbeat Correct Answer: B
  4. (Open-ended challenge) A financial trading dashboard displays live bid/ask prices for 500 stock symbols, updating every 200 ms per symbol. At 50,000 concurrent users, each watching a personalized subset of 10โ€“20 symbols, evaluate the trade-offs between Server-Sent Events and WebSockets for this workload. Consider: total message volume, fan-out architecture, client-side filtering versus server-side subscriptions, and whether the client ever needs to push data to the server. Which pattern would you choose and why?

    • No single correct answer โ€” consider whether per-user subscription filtering on the server reduces SSE stream volume enough to avoid a fan-out broker, versus the complexity WebSockets add for a purely server-to-client workload.


Abstract Algorithms

Written by

Abstract Algorithms

@abstractalgorithms