Skip to content

19 — Real-Time Systems

Real-time systems process and deliver data with minimal delay — typically milliseconds to seconds. They power chat apps, live notifications, collaborative editing, gaming, and live dashboards.

Analogy: A real-time system is like a live conversation vs email. Email (batch) has minutes to hours of delay. A conversation (real-time) has milliseconds of delay — you hear the words almost as soon as they’re spoken.


Building real-time systems is challenging:

  • Low latency requirement — messages must arrive in < 100ms
  • Connection management — millions of persistent connections
  • State synchronization — all clients must see the same state
  • At-least-once delivery — no message loss
  • Scaling — WebSocket connections don’t scale like HTTP

flowchart TB
RT["Real-Time Communication"] --> WebSocket["WebSocket<br/>Full-duplex, persistent<br/>Bidirectional"]
RT --> SSE["Server-Sent Events<br/>One-way (server → client)<br/>HTTP-based"]
RT --> LongPoll["Long Polling<br/>Client polls, server holds<br/>Legacy fallback"]
RT --> WebRTC["WebRTC<br/>Peer-to-peer<br/>Lowest latency"]
WebSocket --> Use_WS["Use: Chat, gaming, live updates"]
SSE --> Use_SSE["Use: Notifications, stock tickers"]
LongPoll --> Use_LP["Use: Fallback when WebSocket unavailable"]
WebRTC --> Use_WR["Use: Video calls, file sharing"]
style RT fill:#7c3aed,color:#fff
style WebSocket fill:#3b82f6,color:#fff
style SSE fill:#059669,color:#fff
style LongPoll fill:#f59e0b,color:#fff
style WebRTC fill:#ef4444,color:#fff
ProtocolDirectionLatencyBrowser SupportUse Case
WebSocketBidirectional< 50ms✅ ExcellentChat, gaming, live apps
SSEServer → Client< 100ms✅ Good (no IE)Notifications, feeds
Long PollingHalf-duplex200ms-5s✅ UniversalFallback
WebRTCPeer-to-peer< 20ms✅ GoodVideo/audio calls

sequenceDiagram
participant Client as Client
participant LB as Load Balancer
participant WS as WebSocket Server
participant PubSub as Pub/Sub (Redis)
participant Other as Other Client
Client->>LB: HTTP Upgrade Request
LB->>WS: Upgrade to WebSocket
Note over Client,WS: Persistent connection established
Client->>WS: Send message
WS->>PubSub: Publish message to channel
PubSub-->>WS: Message routed
WS-->>Client: Acknowledge
Note over WS,PubSub: Pub/Sub broadcasts to all WebSocket servers
PubSub->>Other: Deliver message
Other-->>Client: Message received in real-time ⚡
Note over Client,Other: Millions of concurrent connections handled via horizontal scaling

flowchart TB
Patterns["Real-Time Patterns"] --> PubSub["Pub/Sub Broker<br/>Redis Pub/Sub / Kafka<br/>Broadcast messages<br/>to all subscribers"]
Patterns --> Presence["Presence System<br/>Track online/offline<br/>Active connections<br/>User status"]
Patterns --> Fanout["Fanout on Write<br/>When data changes,<br/>push to all connected<br/>clients"]
Patterns --> CQRS["CQRS + Events<br/>Write events to stream,<br/>read model updated<br/>asynchronously"]
style Patterns fill:#7c3aed,color:#fff
style PubSub fill:#3b82f6,color:#fff
style Presence fill:#059669,color:#fff
style Fanout fill:#f59e0b,color:#fff
style CQRS fill:#ef4444,color:#fff

A single server can handle ~10K-100K concurrent WebSocket connections. To scale beyond that:

flowchart TB
Users["10M Users"] --> LB["Load Balancer<br/>(Sticky sessions or<br/>application routing)"]
LB --> WS1["WebSocket Server 1<br/>100K connections"]
LB --> WS2["WebSocket Server 2<br/>100K connections"]
LB --> WS3["WebSocket Server 3<br/>100K connections"]
LB --> WSN["WebSocket Server N<br/>100K connections"]
WS1 & WS2 & WS3 & WSN --> PubSub["Pub/Sub Backplane<br/>Redis / RabbitMQ / Kafka"]
PubSub --> API["Application Services"]
style Users fill:#f59e0b,color:#fff
style LB fill:#3b82f6,color:#fff
style PubSub fill:#7c3aed,color:#fff
ChallengeSolution
Server affinityClient always connects to same WebSocket server (sticky routing)
Cross-server broadcastPub/sub backplane (Redis Pub/Sub or Kafka) between WebSocket servers
Connection stateStore session state in Redis — not in WebSocket server memory
Graceful closeSend drain signal, let clients reconnect to other servers

flowchart TB
subgraph Online["Online Users"]
U1["User 1 🟢"]
U2["User 2 🟢"]
U3["User 3 🟢"]
end
subgraph Redis_Presence["Redis Presence Store"]
Key1["user:1 → 'online'<br/>TTL: 30s"]
Key2["user:2 → 'online'<br/>TTL: 30s"]
Key3["user:3 → 'online'<br/>TTL: 30s"]
Key4["user:4 → 'away'<br/>TTL: 30s"]
end
subgraph Heartbeat["Heartbeat Process"]
HB["Client sends heartbeat<br/>every 15 seconds"]
HB -->|"Update TTL"| Redis_Presence
Expire["TTL expired →<br/>user marked offline"]
end
Online -->|"Heartbeat"| Redis_Presence
Redis_Presence -->|"Presence updates"| Clients["Other clients<br/>see status changes"]
style Online fill:#059669,color:#fff
style Redis_Presence fill:#7c3aed,color:#fff
style Heartbeat fill:#3b82f6,color:#fff
Presence StrategyHow It WorksProsCons
HeartbeatClient sends “I’m alive” every N secondsSimpleFalse offline if heartbeat delayed
WebSocket disconnectDetect connection closeAccurateNo heartbeat = may miss timeout
HybridHeartbeat + connection stateMost reliableMost complex

DecisionProsCons
WebSocketBidirectional, low latencyConnection management complexity
SSESimpler (HTTP), auto-reconnectServer → client only
PollingSimple to implementLots of wasted requests
Pub/sub backplaneScales WebSocket horizontallyExtra infrastructure (Redis/Kafka)
In-memory stateFastest, simplestLost on server restart, can’t scale

StrategyDescription
Horizontal WebSocket serversMultiple servers behind sticky load balancer
Pub/sub backplaneRedis Pub/Sub or Kafka for cross-server communication
Connection poolingReduce overhead of creating new connections
Binary protocolsUse Protocol Buffers, MessagePack instead of JSON
BackpressureSlow down producers when consumers can’t keep up
Edge deliveryDeploy WebSocket servers at edge (Cloudflare Workers, AWS@Edge)

  1. What’s the difference between WebSockets and Server-Sent Events?
  2. How do you scale WebSocket connections to millions of users?
  3. How would you design a real-time chat system?
  4. How does a presence system (online/offline) work?
  5. What is a pub/sub backplane and why is it needed for real-time systems?

SystemReal-Time Approach
WhatsAppCustom WebSocket implementation, Erlang-based servers
SlackWebSocket for real-time messages, presence via heartbeat
FigmaWebSocket + CRDT for collaborative editing
Twitter/XWebSocket-based streaming API for real-time tweets

  • Real-time = data delivered within milliseconds — users see changes instantly
  • WebSocket = persistent bidirectional connection — best for chat, gaming, live apps
  • SSE = server pushes to client — simpler, good for notifications, feeds
  • Scaling WebSockets needs sticky routing + pub/sub backplane (Redis/Kafka)
  • Presence = knowing who’s online — implemented via heartbeats with TTL in Redis
  • Pub/sub backplane is the key to scaling — it relays messages between WebSocket servers
  • Always handle reconnection gracefully — networks fail, clients move between servers