WebSockets
WebSockets provide message framing over a long-lived bidirectional connection after an HTTP-compatible opening handshake. The protocol solves neither durable delivery nor scalable fan-out by itself. Senior designs separate the connection gateway from durable state and event distribution, specify reconnect/replay semantics, bound slow-consumer buffers, and plan deployments around millions of stateful connections.
How to use this chapter
- Read the mental model and mechanics without taking notes.
- Close the page and explain the topic aloud in five minutes.
- Work the quantitative example on paper.
- Answer the question ladder without revealing the answer signals.
- Complete one design drill and score yourself with the senior checklist.
Learning objectives
- Explain the opening handshake, origin/security model, frames, control frames, fragmentation, and close behavior.
- Compare WebSockets with polling, long polling, Server-Sent Events, gRPC streaming, and WebTransport.
- Design authentication, authorization refresh, heartbeat, reconnect, resume, ordering, and deduplication.
- Scale connection gateways, presence, rooms/topics, and multi-region fan-out.
- Implement backpressure and slow-consumer policies without losing durable messages.
- Operate deploys, load balancers, proxies, and reconnect storms at senior level.
Mental model
A WebSocket is a transport session, not a database or queue. It gives two endpoints a framed full-duplex channel, usually over TCP. Once established, it may live far longer than service deployments, DNS answers, credentials, or backend membership. The architecture must therefore distinguish ephemeral connection state from durable application state.
Core mechanics
Handshake and framing
Classic WebSockets begin with an HTTP/1.1 Upgrade handshake that validates headers and agrees on the protocol. Extensions and subprotocols can be negotiated. HTTP/2 and HTTP/3 use Extended CONNECT mechanisms rather than a connection-wide Upgrade. Intermediaries must explicitly support the relevant mechanism.
Data is carried in text or binary frames; messages can be fragmented. Ping, pong, and close are control frames with special rules. Browser clients mask frames sent to servers. Applications should set message-size limits and validate UTF-8 for text messages to prevent resource abuse.
Connection lifecycle and liveness
A clean close handshake communicates status; abrupt resets and network loss may provide no final message. TCP keepalive is often too slow for product liveness, so gateways send protocol ping/pong or application heartbeats. Heartbeats should be jittered and tuned relative to proxy/NAT idle timeouts.
A liveness timeout proves only that recent messages were not observed; it does not identify which side failed. On reconnect, clients need a strategy: resume a session, fetch current state, replay missed events, or accept loss for ephemeral signals.
Authentication and authorization
Authenticate during handshake with cookies, tokens, or a short-lived ticket. Browser constraints may limit arbitrary headers, and query-string tokens can leak through logs, so signed one-time tickets are often safer. Validate the Origin header for browser clients where appropriate.
Long-lived credentials expire or permissions change. Define reauthentication, token refresh, server-initiated close, and per-message authorization. Do not assume that because a user was authorized to join a room an hour ago they remain authorized forever.
Delivery, ordering, and replay
WebSocket frames over one TCP connection arrive in order, but reconnects, multiple producer paths, and multi-region routing can reorder application events. Assign monotonic sequence numbers within the ordering scope—conversation, document, user stream—and include event IDs for deduplication.
For durable events, persist before announcing success and store a cursor so clients request events after the last acknowledged sequence. For ephemeral presence or typing, newer state can supersede older state; coalescing and dropping are preferable to unbounded queues.
Backpressure and slow consumers
A server may produce faster than a client can receive. Kernel and runtime socket buffers initially hide the mismatch; then per-connection memory grows. Bound queued bytes/messages and choose a policy by event type: coalesce snapshots, drop low-value signals, disconnect and require replay, or pause upstream subscriptions.
Never let one slow client block a room broadcaster synchronously. Fan-out should enqueue independently or use broker partitions, with quotas and fairness. Measure send-queue age and bytes, not only connection count.
Scaling gateways and fan-out
Gateways are stateful because they own live sockets, yet durable truth can remain external. Route a client to any healthy gateway, register presence/connection metadata with leases, and use a pub/sub or log layer to deliver events to gateways hosting interested users. Sticky load balancing is an optimization, not a substitute for shared routing state.
For large rooms, naive publish-to-every-gateway or per-member broker subscriptions can explode. Partition by room/topic, aggregate subscribers per gateway, use hierarchical fan-out, and cache membership. Extremely large broadcasts may use CDN-like edge distribution or periodic state snapshots.
Deployments and regional failure
Connection-aware deploys mark instances draining, stop new accepts, optionally notify clients to reconnect, and wait for a bounded period before closing. Randomize client reconnects and preserve resume tokens. A load balancer health check should remove an instance from new connections before termination.
Multi-region design must define session home, event ordering, and failover. Active connections cannot be transparently moved at the TCP layer; clients reconnect. Keep replay state accessible in the target region or communicate that some ephemeral events may be lost.
Alternatives
Server-Sent Events provide server-to-client text streams over HTTP and automatic reconnect semantics, often simpler for one-way updates. Long polling works through restrictive infrastructure but has request overhead. gRPC streaming is strong for service-to-service typed streams. WebTransport provides streams and datagrams over HTTP/3 in supporting environments. Choose based on directionality, browser support, reliability, caching/proxy needs, and operational maturity.
Decision table
| Decision | Prefer the first option when… | Prefer the second option when… | Senior caveat |
|---|---|---|---|
| WebSocket vs SSE | Bidirectional low-latency messaging or binary frames are required. | Server-to-browser updates dominate and HTTP semantics/simple reconnect are preferred. | SSE connection limits/proxy buffering and auth still need validation; WebSockets add client-to-server abuse surface. |
| Sticky sessions vs any gateway | Local in-memory subscriptions improve efficiency and reconnect churn is low. | Fast failover and operational simplicity favor external routing state. | Use stickiness as a hint; durable/replay state must survive gateway loss. |
| Persist every event vs ephemeral state | Messages must survive disconnect and be audited/replayed. | Newest state supersedes old updates and loss is acceptable. | Classify by event type; mixing durable chat with ephemeral typing in one queue causes wrong trade-offs. |
| Per-user stream vs per-room stream | Ordering and authorization are user-centric. | Shared room ordering and broadcast efficiency dominate. | Cross-room ordering is usually unnecessary and expensive; define exact scope. |
| Disconnect slow client vs buffer | Freshness and fleet protection dominate. | Short network stalls should be absorbed within a strict bound. | Persist durable messages elsewhere and expose resume cursor before disconnecting. |
| Single region session vs nearest region | Strong ordering and simple state ownership dominate. | Latency and regional continuity justify distributed session/data design. | Nearest connection does not imply nearest authoritative write region. |
Quantitative reasoning
Failure modes and production signals
| Failure mode | What users see | Likely cause | Mitigation / design response | Useful signals |
|---|---|---|---|---|
| Slow-consumer buildup | Lagging updates then disconnects/OOM | Unbounded per-socket queue | Bound bytes/age, coalesce/drop, replay durable data, disconnect | Queued bytes, oldest send age, zero-window, disconnect reason |
| Reconnect storm | Handshake/auth saturation | Region/LB outage or deploy closes many sockets | Jitter/backoff, admission, session resumption, gradual drain/recovery | Connections/s, TLS CPU, auth QPS, retry cohorts |
| Lost events after reconnect | Gaps in chat/state | No durable cursor/replay or ack ambiguity | Sequence IDs, persist-first, client cursor, gap detection/snapshot | Gap requests, duplicate rate, replay lag |
| Presence ghosting | Users appear online after disconnect | No lease/expiry or missed close | Lease heartbeat and TTL, reconciliation, multi-device model | Expired leases, presence age, gateway registration count |
| Proxy idle timeout | Regular disconnect interval | Intermediary closes quiet connection | Heartbeat below timeout, align settings, observe close path | Connection lifetime histogram, close codes, LB logs |
| Authorization drift | Revoked user continues receiving data | Auth checked only at handshake | Short leases/token refresh, revocation channel, per-subscription checks | Session credential age, revocation latency, unauthorized attempts |
Senior-level lenses
Classify each event by value
Chat messages, financial updates, typing indicators, cursor positions, and presence need different persistence and backpressure policies. Build message classes with priority, durability, coalescing, and replay behavior instead of one global “reliable WebSocket” promise.
Use sequence scopes, not global sequence
A global total order is expensive and usually unnecessary. Per-conversation or per-document order lets the system partition. Clients can merge independent streams using timestamps only for presentation, while correctness uses explicit causal/version metadata where needed.
Gateway loss should be routine
The gateway is a cache of live routing state. Leases expire, clients reconnect, and durable events replay. Avoid synchronous global cleanup on crash. Test thousands of simultaneous gateway losses and broker partition reassignments.
Presence is approximate
Online status is usually a lease-based estimate with a freshness window, especially across devices and regions. Define states such as online, recently active, and offline; avoid promising instantaneous truth that requires global synchronous coordination.
Deployment is a protocol event
Long-lived clients may span versions. Version messages/subprotocols, keep backward compatibility, communicate drain/reconnect, and make resume tokens valid across old and new gateway fleets. A rollout that simply kills pods is an availability design flaw.
Abuse scales with connection longevity
Authenticate before expensive subscriptions, cap rooms/topics and inbound rate, validate message size/schema, enforce tenant quotas, and defend against idle-connection and fan-out amplification attacks. Per-connection limits are not enough when one tenant opens millions.
Interview question ladder
What does WebSocket add compared with ordinary HTTP request/response?
Show strong-answer signals
A long-lived full-duplex framed channel after handshake. It does not add durable delivery, replay, authorization model, or scalable fan-out automatically.
What are ping and pong frames used for?
Show strong-answer signals
Protocol-level liveness/keepalive and latency measurement; distinguish from application semantic heartbeats and intermediary idle timeouts.
How is message ordering handled on one WebSocket connection?
Show strong-answer signals
Frames/messages are delivered in TCP order, but fragmentation, reconnect, multiple producers/connections, and regions require application sequence semantics.
How do you authenticate a browser WebSocket safely?
Show strong-answer signals
Cookie with CSRF/origin controls or short-lived one-time ticket; TLS; validate Origin; avoid long-lived query tokens/log leakage; authorize subscriptions/messages.
What do you do with a slow WebSocket client?
Show strong-answer signals
Bound queue; coalesce/drop ephemeral data; persist durable messages separately; pause subscription if possible; disconnect with resume cursor; metrics and quotas.
WebSocket or SSE for stock-price updates?
Show strong-answer signals
If one-way updates and browser simplicity dominate, SSE; if bidirectional commands/binary/very low overhead needed, WebSocket. Discuss auth, reconnect, proxy, event IDs, and scale.
Design chat delivery across 100 gateway nodes.
Show strong-answer signals
Any gateway accepts connection, presence lease maps users to gateways, durable message log/store with conversation sequence, pub/sub to interested gateways, ack/read receipts, dedupe, replay, slow-consumer policy.
How do you deploy a new gateway version without a reconnect storm?
Show strong-answer signals
Mark drain, stop new connections, bounded natural drain, server reconnect hint with jitter, canary percentage by connections, session/token compatibility, capacity headroom, rollback.
A large room causes broker and gateway overload. Redesign fan-out.
Show strong-answer signals
Aggregate per gateway, partition/hierarchical fan-out, cap/segment rooms, snapshot+delta, edge distribution, coalesce, priority, and measure deliveries rather than messages.
How does a reconnecting client know whether a sent command succeeded?
Show strong-answer signals
Client operation ID/idempotency, server durable status, ack only after defined commit, query/replay by ID, distinguish transport ack from business result.
Design multi-region collaborative editing over long-lived connections.
Show strong-answer signals
Nearest gateways, document ownership/replicated operation log, sequence/version or CRDT/OT semantics, reconnect cursor/snapshot, auth changes, regional partition behavior, and gateway-independent durable state.
Create a capacity and isolation model for 20M connections across free and enterprise tenants.
Show strong-answer signals
Per-connection memory/heartbeat, per-tenant connection and fan-out quotas, dedicated pools/regions for enterprise, fair queues, cost attribution, admission under failover, and migration between tiers.
Design drills
Design live scores for 10M concurrent viewers, with 1,000 games, comments, and score corrections. Decide WebSocket/SSE usage, fan-out hierarchy, replay, cache snapshots, and correction ordering.
What the interviewer is testing
Mass fan-out, durable versus ephemeral events, edge distribution, and correctness of corrections.
Design multi-device presence for 100M users. Define heartbeat interval, lease model, privacy rules, regional aggregation, and what ‘online’ means during partitions.
What the interviewer is testing
Approximate state, fleet cost, authorization, and avoiding global synchronous coordination.
A gateway fleet OOMs during a mobile-network degradation. Produce an incident diagnosis and permanent design changes at socket, queue, broker, and product levels.
What the interviewer is testing
Backpressure propagation, event classification, quotas, and operational signals.
Common weak answers and how to improve them
“WebSocket guarantees delivery.”
Show the stronger answer
Only the live ordered transport; durable application delivery needs persistence, IDs, acknowledgments, and replay.
“Use sticky sessions.”
Show the stronger answer
Explain failover, external routing state, replay, and why stickiness is only an optimization.
“Buffer until the client catches up.”
Show the stronger answer
Set byte/age bounds and classify drop/coalesce/disconnect behavior to protect the fleet.
“Ping every second to detect failures.”
Show the stronger answer
Calculate packet/CPU/battery cost and false positives; align with product RTO and intermediary timeouts.
“All messages need global order.”
Show the stronger answer
Define the smallest required ordering scope and partition accordingly.