Problem Statement: Why We Need Socket Scaling

  • Single server limitation: A single Node.js + Socket.IO instance can typically handle ~10K–30K concurrent connections before event‑loop delays, memory pressure, and OS file‑descriptor limits cause performance degradation.
  • Cross-server communication gap: Without synchronization, events emitted on one instance (e.g. user in room on Server A) won’t reach clients connected to another instance (Server B), creating message silos.
  • Resilience & high availability: Heavy load demands horizontal scaling and resilience, including fail‑over across multiple node instances.

Solution: Horizontal Scaling Using Socket.IO + Redis Pub/Sub Adapter

1. Deploy multiple Socket.IO server instances (Node.js cluster or separate nodes)

Use either:
  • Node.js native cluster module to run workers per CPU core
  • Multiple separate Socket.IO processes behind a load balancer (with sticky sessions)

2. Configure Redis adapter for cross-instance messaging

Use @socket.io/redis-adapter (version 7+ compatible with Socket.IO 4.x). It binds two Redis clients (pub and sub) and sets up Pub/Sub channels so that broadcasts or room emissions propagate across nodes.

3. Redis Pub/Sub flow:

  • When Server A emits io.to('room1').emit(...):
    • It broadcasts locally to connected clients in room1
    • It publishes the same event via Redis channel
  • Other servers subscribed on that channel receive the message and emit it to their local clients in room1
  • No persistent data is stored in Redis—only ephemeral Pub/Sub messages

4. (Optional) Sharded adapter for Redis cluster scale

With Redis 7.0+, use createShardedAdapter() to distribute channels across shards—useful in large-scale setups with many rooms, including private/direct messages.

5. (Optional) External emitter

Use @socket.io/redis-emitter from a separate process (outside Socket.IO servers) to publish events directly to Redis, enabling loosely coupled services to push to clients.

Diagram of the Flow

Client A               Client B
   │                      │
  Server A             Server B
     ├── local emit ──▶  │
     │                   │
     │  publish to Redis Pub/Sub channel
     └──▶ Redis ────────▶┬─ deliver to Server B
                         └─ deliver back to Server A
     └── Server B broadcasts to its local clients
This architecture ensures that regardless of which server a client connects to, they will receive real-time events from any other client or service in the system.