Pub/Sub & Scaling Real-Time Apps
๐ก Pub/Sub & Scaling Real-Time Apps
web-sockets1-7 named a "Redis pub/sub adapter" as the fix for rooms breaking across multiple WebSocket servers, without teaching pub/sub itself. This chapter builds PUBLISH/SUBSCRIBE from first principles, then shows exactly how it solves that scaling problem.
The Problem: WebSockets Don't Scale Across Servers by Default
A WebSocket connection is tied to one specific server process. If a chat application runs on multiple server instances behind a load balancer, a client connected to Server A and a client connected to Server B are, as far as either server is concerned, on entirely separate islands โ Server A has no built-in way to know Server B's clients even exist, let alone deliver a message to them. This is exactly the "rooms break across servers" gotcha web-sockets1-7 flagged without solving.
PUBLISH & SUBSCRIBE
Redis pub/sub is straightforward: a client SUBSCRIBEs to a named channel; any client PUBLISHes a message to that channel; every currently subscribed client receives it immediately.
Pub/sub is fire-and-forget: if no one happens to be subscribed at the moment a message is published, that message is simply gone โ never delivered, never stored. This is a fundamentally different guarantee from Chapter 7's queues, where messages persist until a consumer actually processes them.
Using Redis Pub/Sub to Bridge Multiple Servers
The fix for web-sockets1-7's scaling problem: every WebSocket server instance also subscribes to a shared Redis channel. When a client sends a chat message, the server it's connected to publishes that message to Redis โ and Redis fans it out to every subscribed server, including ones the original client never touched.
The Full Flow: Client A โ Server B
- Client A sends a chat message over its WebSocket connection to Server A.
- Server A relays it to its own local clients and
PUBLISHes it to a shared Redis channel, e.g.chat:room1. - Redis delivers that published message to every subscriber โ including Server B, which also subscribed to
chat:room1on startup. - Server B receives the message from Redis and relays it over its own WebSocket connections to Client B, who was never connected to Server A at all.
This is exactly what a "Redis pub/sub adapter" (Socket.IO's own included adapter is a real example) automates under the hood โ every server instance subscribes to the same channels, and Redis becomes the shared nervous system connecting servers that otherwise know nothing about each other.
Pub/Sub vs. Queues (Chapter 7)
Pub/Sub
Fire-and-forget, no persistence โ a message published with no subscriber listening is lost forever. Right for real-time broadcast where late delivery is meaningless anyway.
Queue (Lists / Streams)
Messages persist until a consumer processes them, even if no consumer is currently connected. Right when a message must eventually be handled, not just broadcast live.
| Command | Purpose |
|---|---|
SUBSCRIBE channel | Listen for messages on a channel |
PUBLISH channel message | Send a message to every current subscriber of a channel |
UNSUBSCRIBE channel | Stop listening to a channel |
PSUBSCRIBE pattern | Subscribe to every channel matching a pattern (e.g. chat:*) |
It's an easy mistake to assume a message published to a channel will still be there when a subscriber connects later โ it won't. If Server B's subscription drops (a restart, a network blip) at the exact moment a message is published, that message is simply gone for Server B, with no way to retrieve it afterward. For real-time broadcast where only "right now" matters (a live chat message, a live cursor position), this is fine โ but anything that genuinely needs to survive a disconnected consumer needs Chapter 7's queue-based approach instead, not pub/sub.
๐ป Coding Challenges
Challenge 1: Subscribe and Publish
Write the redis-cli commands needed for one client to subscribe to a channel called notifications, and for another client to publish the message "new order placed" to it.
Goal: Practice the basic SUBSCRIBE/PUBLISH pair.
Challenge 2: Trace the Cross-Server Flow
Using this chapter's four-step flow, explain what happens when Client A (connected to Server A) sends a message, and Client B (connected to Server B) is the intended recipient โ assume both servers subscribe to the same Redis channel.
Goal: Practice tracing the full publish-and-fan-out sequence that bridges two otherwise-isolated servers.
Challenge 3: Pub/Sub or Queue?
For each, say whether Redis pub/sub or a queue (Chapter 7) is the right fit, and why: (a) broadcasting a live "user is typing" indicator in a chat app, (b) processing a payment that must eventually succeed even if the payment worker was briefly offline.
Goal: Practice applying the fire-and-forget vs. persistent-until-processed distinction to realistic scenarios.
๐ฏ What's Next
The next chapter is Redis as a Queue: Lists vs. Streams โ simple list-based queues, Redis Streams, and consumer groups, deepening node3-6's brief mention of Redis Streams.