Bird
Raised Fist0

WebSockets vs Long Polling vs Server-Sent Events - When to Use Each

HLDmediumInterview freq: common
Choose your preparation mode4 modes available
🏗️
WebSockets vs Long Polling vs Server-Sent Events - When to Use Each
Choosing the right real-time communication protocol based on scale, latency, and client capabilities
mediumNetworking and ProtocolsFreq: common
Prerequisites:HTTPTCP
⚙️
Functional Requirements
  • Support real-time bidirectional communication between clients and servers.
  • Allow fallback to alternative protocols if primary protocol unsupported by client or network.
  • Deliver messages with low latency (target <100ms P99 end-to-end).
  • Handle client presence and connection state efficiently.
  • Support message broadcasting to multiple clients (fan-out).
  • Provide reliable message delivery guarantees (at least once).
📊
Non-Functional Requirements
  • Support up to 2 billion daily active users (DAU).
  • Handle peak write throughput of 925K messages per second.
  • Ensure 99.99% availability for real-time messaging endpoints.
  • Maintain end-to-end latency under 100ms P99 for message delivery.
  • Scale horizontally with minimal manual sharding.
❓
Clarifying Questions to Ask
  • What is the expected message size and frequency per user?
  • Are clients mostly browsers, mobile apps, or IoT devices?
  • Is bidirectional communication mandatory or is server-to-client sufficient?
  • What network environments must be supported (e.g., proxies, firewalls)?
  • Is message ordering or exactly-once delivery required?
  • What is the expected client connection duration and churn rate?
Out of Scope
✗ Designing the full messaging persistence and history retrieval system.
✗ End-to-end encryption or advanced security protocols beyond TLS.
✗ Client-side UI rendering or SDK implementation details.
✗ Offline message queuing and retry mechanisms.
📌
Assumptions
  • 2 billion DAU
  • 40 messages per user per day
  • 100 bytes average message size
  • Peak traffic concentrated in 4 hours daily (peak factor 4)
⚡
QPS Calculation
write qps2B × 40 / 86400 ≈ 925,926 msg/sec
peak write qps925,926 × 4 ≈ 3.7M msg/sec
read qpsAssuming 1 read per write, read_qps = 3.7M msg/sec
💾
Storage Estimate
daily storage bytes2B × 40 × 100 = 8TB/day
retention days7
total storage bytes8TB × 7 = 56TB
with replication 3x56TB × 3 = 168TB
🖥️
Server Estimate
websocket serversAssuming 10K concurrent connections per server, peak 100M concurrent users → 10,000 servers
load balancers1 per 100 websocket servers → 100 load balancers
🏗️
Architecture Diagram
Architecture Diagram
          +----------------+
          |  Load Balancer |
          +-------+--------+
                  |
      +-----------+------------+
      |                        |
+-----v-----+            +-----v-----+
| WebSocket |            | Long Poll |
|  Server   |            |  Server   |
+-----+-----+            +-----+-----+
      |                        |
      |                        |
 +----v----+             +-----v-----+
 | Message |             | SSE Server|
 | Broker  |             +-----------+
 +----+----+
      |
 +----v----+
 | Storage |
 |  (Kafka |
 |  + DB)  |
 +---------+
🧩
Components
Load Balancer
Distributes incoming client connections to appropriate protocol servers based on client capability and network conditions.
Why thisNginx or Envoy supports protocol-aware routing and health checks for WebSocket and HTTP long polling.
Why notAWS ELB lacks fine-grained protocol routing and sticky session support needed for WebSocket affinity.
WebSocket Server
Maintains persistent bidirectional TCP connections for low-latency real-time messaging.
Why thisUsing Node.js with uWebSockets.js for high concurrency and low memory footprint per connection.
Why notApache HTTP Server lacks efficient WebSocket support and scales poorly with millions of concurrent connections.
Long Polling Server
Handles HTTP long polling fallback for clients or networks that do not support WebSockets or SSE.
Why thisNginx with Lua scripts or Express.js can efficiently manage long polling with connection reuse and timeout management.
Why notTraditional HTTP servers like Apache are inefficient for long polling due to thread-per-connection model.
Server-Sent Events (SSE) Server
Supports unidirectional server-to-client streaming over HTTP for clients that support SSE but not WebSockets.
Why thisUsing Go net/http package with native SSE support for lightweight, scalable streaming.
Why notWebSocket servers are overkill for unidirectional streaming and consume more resources.
Message Broker
Decouples message ingestion from delivery, enabling scalable fan-out and persistence.
Why thisApache Kafka supports high throughput (millions of msgs/sec), partitioning, and consumer groups for fan-out.
Why notRabbitMQ does not scale linearly beyond hundreds of thousands of messages per second.
Storage
Stores message history and metadata for retention and replay.
Why thisCassandra provides linear write scalability and tunable consistency for 168TB replicated data.
Why notPostgreSQL requires complex manual sharding at 3.7M writes/sec; B-tree writes don't scale linearly.
🔄
Data Flow
1
Client → Load Balancer
Client initiates connection; Load Balancer detects protocol support (WebSocket, SSE, or Long Polling).
Protocol detection based on HTTP headers and network conditions.
2
Load Balancer → Appropriate Protocol Server
Routes connection to WebSocket, SSE, or Long Polling server accordingly.
Ensures sticky sessions for WebSocket connections.
3
Protocol Server → Message Broker (Kafka)
Server publishes incoming messages to Kafka topics partitioned by conversation or channel.
Enables asynchronous decoupling and scalable fan-out.
4
Message Broker → Protocol Servers
Servers consume messages from Kafka to deliver to connected clients.
Supports multiple consumers for broadcasting.
5
Protocol Servers → Clients
Deliver messages over persistent WebSocket, SSE stream, or long polling response.
Ensures low latency and reliability.
6
Message Broker → Storage (Cassandra)
Persist messages asynchronously for retention and replay.
Storage is eventually consistent with message delivery.
🗄️
Messages
PK: channel_id
message_idchannel_idtimestampsender_idcontent
Stores messages per channel ordered by timestamp for efficient retrieval.
🗄️
Clients
PK: client_id
client_idconnection_start_timeprotocolstatus
Tracks client connection state and protocol used for routing and presence.
🔌
Connect
Request
{
  "client_id": "string",
  "protocol": "string (websocket|sse|longpoll)",
  "auth_token": "string"
}
Response
{
  "connection_id": "string",
  "status": "string"
}
Establishes a connection using the specified protocol with authentication.
🔌
SendMessage
Request
{
  "connection_id": "string",
  "channel_id": "string",
  "content": "string"
}
Response
{
  "message_id": "string",
  "status": "string"
}
Sends a message to a channel via an established connection.
🔌
ReceiveMessages
Request
{
  "connection_id": "string",
  "last_received_timestamp": "long"
}
Response
{
  "messages": "array of message objects"
}
Fetches messages after the given timestamp for the connection.

Practice

(1/5)
1. In the DNS resolution chain, at step 4 the recursive DNS server receives a referral response from the root server pointing to a TLD server. What state does the recursive server enter immediately after receiving this referral?
easy
A. It caches the referral to the TLD server and initiates a query to the TLD server
B. It discards the referral and retries querying the root server
C. It caches the IP address of the root server and returns it to the client
D. It forwards the referral directly to the client without caching

Solution

  1. Step 1: Understand recursive server behavior on referral

    When the recursive DNS server receives a referral from the root server, it caches the referral information (the TLD server's IP) and then queries the TLD server itself.
  2. Step 2: Eliminate incorrect states

    It does not cache the root server IP (already known), nor does it discard the referral or forward it directly to the client. The recursive server handles the full resolution chain transparently.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Recursive server caches referral and queries next server [check]
Hint: Recursive server caches referrals and queries next hop [check]
Common Mistakes:
2. Without a message queue like Kafka in a chat system, what exactly breaks in message delivery?
medium
A. Alice's send blocks until Bob's server responds; if Bob's server crashes, message is lost with no retry
B. Messages are duplicated due to lack of idempotency
C. Messages are encrypted incorrectly causing security breaches
D. Delivery workers lose track of message ordering causing out-of-order display

Solution

  1. Step 1: Role of Kafka in decoupling send and delivery

    Kafka buffers messages asynchronously, preventing sender blocking on recipient availability.
  2. Step 2: Consequence of removing Kafka

    Sender must synchronously wait for recipient response; if recipient crashes, message is lost with no retry.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    No queue causes synchronous blocking and message loss on recipient failure [check]
Hint: No queue means sender blocks and loses messages if recipient crashes [check]
Common Mistakes:
3. Which monitoring strategy best prevents failover incidents like GitHub's database crash by detecting anomalies early?
medium
A. Periodic manual health checks by DBAs
B. Weekly backup verification reports
C. Real-time metrics with alerting on leader election delays
D. Client-side error logging without centralized monitoring

Solution

  1. Step 1: Importance of monitoring leader election

    Real-time metrics detect leader election delays indicating failover issues early.
  2. Step 2: Evaluate other options

    Manual checks (A) are slow; backup reports (C) don't catch live failover issues; client logs (D) lack centralized alerting.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Real-time alerting enables proactive failover management [check]
Hint: Real-time alerts catch failover delays early
Common Mistakes:
4. You must implement a distributed lock for a system with high contention and strict latency requirements. Which approach is best and why?
medium
A. Use Redis SETNX with a fixed TTL to minimize latency
B. Use a consensus-based lock service like etcd to ensure correctness despite latency
C. Use a database row lock with retries to handle contention
D. Use a local in-memory lock combined with periodic heartbeat checks

Solution

  1. Step 1: Evaluate Redis SETNX under high contention

    Redis SETNX with TTL (A) is fast but can cause split-brain and stale locks under network partitions, violating correctness.
  2. Step 2: Consider consensus-based lock service

    Consensus-based services like etcd (B) provide strong consistency and fault tolerance, ensuring correctness even if latency is higher.
  3. Step 3: Assess database row locks and local locks

    Database locks (C) have high latency and risk deadlocks; local locks (D) do not coordinate across nodes, failing correctness.
  4. Final Answer:

    Option B -> Option B
  5. Quick Check:

    Consensus ensures correctness under contention despite latency [check]
Hint: Consensus beats speed for correctness under contention [check]
Common Mistakes:
5. At 10x scale, which component in the webhook delivery system is most likely to fail first and why?
hard
A. The database, due to increased write contention on event status updates
B. The load balancer, as it cannot efficiently route millions of concurrent webhook requests
C. The Delivery Workers, because they maintain stateful connections per subscriber limiting horizontal scaling
D. The retry queue, since it cannot handle the exponential growth of failed events

Solution

  1. Step 1: Identify stateful bottleneck at scale

    Delivery Workers hold stateful connections (e.g., HTTP keep-alive) per subscriber, limiting resharding and horizontal scaling.
  2. Step 2: Compare other components

    Databases can be sharded; load balancers scale horizontally; retry queues are usually distributed and scalable.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Stateful Delivery Workers -> scaling bottleneck [check]
Hint: Stateful workers block scaling first [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard