1. URL Shortener vs. Real-Time Chat: A Fundamental Paradigm Shift
In the previous lesson, we built a URL shortener using the traditional request-response model:
Instant messaging requires a completely different architectural paradigm. Two or more humans are engaged in bi-directional, real-time communication:
- Alice transmits a message, and it must appear on Bob's screen within milliseconds.
- Some users are online, others are offline, and many transition between flaky Wi-Fi and mobile cells.
- Users demand delivery receipts: Sent (✓), Delivered (✓✓), and Read (✓✓ blue ticks).
- Message ordering must remain strictly preserved regardless of network arrival jitter.
How do we design a messaging platform capable of sustaining millions of open connections, guaranteeing zero message loss, and delivering messages globally in under 100 milliseconds?
2. Requirements & Back-of-the-Envelope Capacity Estimations
Functional Requirements
- 1-on-1 & Group Messaging: Users can send and receive text and media in real time.
- Delivery Receipts: Sent (stored on server), Delivered (received by client device), Read (opened by user).
- User Presence: Online, offline, and last seen timestamps.
- Offline Storage & Sync: Offline users receive push alerts; messages sync seamlessly upon reconnect.
- Media Sharing: Images, voice notes, and videos supported via asynchronous pipelines.
Non-Functional Requirements
- Ultra-Low Latency: End-to-end delivery latency must remain sub-100ms globally.
- Zero Message Loss: High durability; messages must survive gateway or node crashes.
- Deterministic Message Ordering: Messages within a conversation must render in the exact order sent.
- High Concurrency: Sustaining millions of active, simultaneous persistent connections.
Daily Text Storage: 2 Billion × 100 bytes = 200 GB/day (~73 TB/year). Fits cleanly into distributed NoSQL wide-column stores.
3. Protocol Selection: Why Traditional HTTP Fails
Standard HTTP is half-duplex and client-initiated. A server cannot push data to a client without the client first requesting it.
The client queries the server every 2 seconds: "Any new messages?" Most responses return empty, wasting client battery, consuming mobile cellular bandwidth, and saturating server CPU with HTTP header parsing.
The server holds the HTTP connection open until a message arrives, responds, and closes. The client must immediately re-establish a new HTTP request. Frequent TLS re-handshakes add severe network overhead.
WebSockets establish a persistent, bidirectional, full-duplex TCP stream following an initial HTTP 101 Upgrade handshake. Once established, frame overhead drops to just 2 to 14 bytes.
✓ Sub-millisecond server push | ✓ Minimal bandwidth | ✓ Low mobile battery consumption4. The Message Lifecycle: Why Persist Before Delivery?
When Alice sends a message, should the chat server immediately forward it to Bob in memory?
If the server receives Alice's message in RAM and crashes before completing delivery to Bob, the message is permanently lost. Alice's client assumes delivery, while Bob never receives the message.
Production messaging systems enforce: "Persist First, Deliver Second":
Alice WebSocket Message
|
v
Chat Gateway Server
|
+--- 1. Validation & Content Security Filter
|
+--- 2. Generate Distributed Unique Message ID (Snowflake)
|
+--- 3. Commit to Durable Database (Status: SENT ✓)
|
+--- 4. Attempt Real-Time Push to Recipient
5. Multiple Chat Servers & Distributed Presence
With millions of concurrent users, a single server cannot hold all WebSocket connections. We maintain a fleet of connection gateways:
Alice is connected to Chat Server 1. Bob is connected to Chat Server 3. When Alice sends a message to Server 1, how does Server 1 locate Bob's active socket across the fleet?
The Presence Registry (Redis Cluster)
Whenever a client connects, the gateway records the active mapping in an in-memory Redis cluster:
Value: { "server_id": "chat-server-3", "status": "online", "last_heartbeat": 1718000000 }
Message Routing Broker (Redis Pub/Sub or Kafka)
Chat Server 1 does not establish direct TCP links with every other server. Instead, it publishes to a central message broker:
Alice ➔ Chat Server 1
|
v (Queries Redis: "Where is Bob connected?")
Redis Presence ➔ "Bob is on Server 3"
|
v
Publish to Message Broker (Channel: "server:chat-3")
|
v
Chat Server 3 (Consumes Event)
|
v (Pushes over Bob's active WebSocket)
Bob's Device!
6. Handling Offline Users: Push Notifications & Synchronization
If Bob is offline (no active socket registered in Redis):
- The message remains safely stored in the database with status
SENT. - The gateway publishes an event to the Push Notification Service.
- Apple APNs or Google FCM dispatches a lightweight alert to Bob's device: "Alice sent you a message".
The Offline Synchronization Protocol
When Bob opens the application, he establishes a fresh WebSocket connection and executes a catch-up sync:
The server streams all unread messages in bulk. This decouples Real-Time Delivery (pushing to active sockets) from Synchronization (pulling missed state upon reconnect).
7. Message Ordering & Idempotency
If Alice rapidly transmits: 1. "Where are you?", 2. "Don't be late", 3. "I'm leaving".
If network jitter causes message 3 to arrive before message 1, conversational context breaks.
Device clocks are untrusted (users change local time), and distributed server clocks experience clock drift. To maintain deterministic ordering, we assign Monotonic Sequence Numbers or Twitter Snowflake IDs per conversation. The client application sorts by sequence ID before rendering.
Duplicate Prevention via Idempotency Keys
On flaky mobile networks, Alice's phone might retry sending a message because it didn't receive the server's ACK in time.
Each message carries a client-generated UUID (client_msg_id). If the server receives an existing ID, it acknowledges receipt without creating a duplicate record in storage.
8. Media Handling: Decoupling Binary Uploads
Never pipe large binary files (images, audio, video) through the WebSocket chat gateways! Large binaries saturate socket buffers and starve real-time text frames.
- Request Presigned URL: Client asks the REST API for an upload token:
POST /api/v1/media/upload-url. - Direct S3 Upload: Client uploads the raw binary directly to AWS S3 / Cloud Storage, bypassing chat servers.
- Lightweight Message Metadata: Client sends a tiny JSON message over the WebSocket containing the media URL and a blurhash thumbnail.
- Edge CDN Download: Recipients download media from global CDN edge caches.
9. Group Chats & Fan-Out Dynamics
In a 10-person group, when Alice sends a message, the server replicates it across 9 active connections (Fan-Out on Write). This is fast and simple.
However, in public channels with 100,000+ members (e.g. Telegram broadcast channels), writing 100,000 socket copies causes catastrophic write amplification. Large channels rely on Fan-Out on Read, where messages append once to a channel timeline and active members pull or stream updates.
10. Complete Real-Time Chat System Architecture Blueprint
MOBILE / WEB CLIENTS
|
v
Load Balancer (TLS & WSS Edge)
|
+------------------------+------------------------+
| |
v v
[ WebSocket Gateway 1 ] [ WebSocket Gateway 2 ]
(Holds Long-Lived Sockets) (Holds Long-Lived Sockets)
| |
+------------------------+------------------------+
|
+------------------+------------------+
| |
v v
[ In-Memory Presence Store ] [ Message Broker Cluster ]
(Redis Cluster: User ➔ Server) (Kafka / RabbitMQ / PubSub)
|
+-----------------------+-----------------------+
| |
v v
[ Chat Persistence Workers ] [ Push Notification Workers ]
| |
v v
[ Distributed NoSQL Store ] [ APNs / FCM ]
(Cassandra / ScyllaDB / DynamoDB) |
v
Offline Users
[ Media Pipeline: S3 Object Storage + Global CDN Edge Caching ]
[ Observability: Prometheus Sockets Metric + Jaeger Distributed Tracing ]
11. The Three-Layer Chat Mental Model
Interactive Chat Architecture Workbench
Simulate real-time WebSocket routing, test message ordering buffers, and calculate concurrency capacity
Concept Check: Real-Time Architecture Quiz
Verify your architectural reasoning with 3 scenario-based questions
Why are WebSockets preferred over short polling for real-time mobile messaging platforms?
Alice is connected to Chat Server 1 and Bob is connected to Chat Server 3. How does Server 1 route Alice's message to Bob?
Why should large media attachments (50MB videos) be uploaded directly to Object Storage (S3) instead of streaming through WebSocket chat gateways?
Designing a Social Media Feed — How to Design a Scalable News Feed like Facebook or X
We have conquered real-time messaging. Next, we confront one of social media's greatest engineering challenges: When a user opens their app, which posts render first? Fan-Out on Write vs. Read, feed ranking pipelines, and generating personalized feeds for millions of users in milliseconds!