Scaling WebSockets to 1,000,000 Concurrent Connections: Redis PubSub, Centrifugo & Socket.IO in 2026

A comprehensive real-time systems engineering guide to scaling WebSockets to 1M concurrent connections: horizontal cluster sharding, Redis/NATS backplanes, uWebSockets.js, Centrifugo, and Linux kernel TCP tuning.
Scaling WebSockets to 1,000,000 Concurrent Connections: Redis PubSub, Centrifugo & Socket.IO in 2026
In modern interactive web and mobile platforms (collaborative workspaces, crypto trading exchanges, live sports streaming, and multiplayer gaming), real-time bidirectional communication is essential.
However, scaling persistent WebSocket TCP connections is fundamentally different from scaling stateless HTTP REST APIs:
- Persistent File Descriptors (Sockets): In HTTP, a connection opens, returns JSON in 20ms, and closes. In WebSockets, 1,000,000 users hold 1,000,000 persistent open TCP sockets simultaneously for hours.
- The Inter-Server Broadcast Challenge: User A is connected to Node Pod 1 in Tokyo, while User B is connected to Node Pod 4 in Frankfurt. When User A sends a chat message to a shared room, how does Pod 1 broadcast the message to Pod 4 instantly?
- Memory & Kernel Exhaustion: At 1,000,000 open sockets, default Linux kernel TCP socket buffers and JavaScript memory objects can consume over 64GB of RAM and hit OS
ulimitfile descriptor caps, crashing the cluster.
In 2026, Architecting 1,000,000 Concurrent WebSockets is a Solved Systems Engineering Discipline.
Top-tier platforms deploy a Decoupled Three-Tier Topology:
- High-Performance Data Plane: uWebSockets.js (C++ bindings) or Centrifugo (Go) delivering sub-millisecond message fan-out with minimal RAM footprint (~2KB per socket).
- Distributed Pub/Sub Backplane: Redis Cluster or NATS JetStream routing cross-node room broadcasts across global server fleets.
- Optimized Linux Kernel Tuning (
sysctl&ulimit): Tuning TCP receive buffers,somaxconn, and epoll queues to support millions of open file handles.
In this deep systems architecture guide, we break down the complete 1M-connection infrastructure blueprint, Linux kernel parameters, and production code engineered at MojoStudio.
1. The 1,000,000 Connection Scaled Architecture Topology
+-----------------------------------------------------------------------------------------+
| 1,000,000 Concurrent WebSocket Distributed Topology |
+-----------------------------------------------------------------------------------------+
[1,000,000 CONCURRENT CLIENTS (Browsers, Mobile Apps, Desktop)]
|
v (TLS 1.3 Termination & TCP Layer 4 Load Balancing)
+-----------------------------------------------------------------+
| CLOUD NLB / HAPROXY (TCP Load Balancer with IP Hash Routing) |
+-----------------------+-----------------------------------------+
|
+---------------+---------------+---------------+
| (200k Sockets)| (200k Sockets)| (200k Sockets)| (200k Sockets each!)
v v v v
+---------------+---------------+---------------+---------------+
| WEBSOCKET POD | WEBSOCKET POD | WEBSOCKET POD | WEBSOCKET POD | ... (5 Pods Total)
| (uWebSockets) | (uWebSockets) | (uWebSockets) | (uWebSockets) |
+-------+-------+-------+-------+-------+-------+-------+-------+
| | | |
+---------------+---------------+---------------+
|
v (High-Speed Pub/Sub Broadcast Backplane: 2M Msg/Sec)
+-----------------------------------------------------------------+
| DISTRIBUTED PUB/SUB BACKPLANE (Redis Cluster / NATS JetStream) |
| - Routes cross-pod channel broadcasts in sub-2 milliseconds! |
+-----------------------------------------------------------------+2. Choosing the WebSocket Engine: uWebSockets vs Centrifugo vs Socket.IO
+-----------------------------------------------------------------------------------------+
| WebSocket Technology Comparison Matrix (2026) |
+-----------------------------------------------------------------------------------------+| Dimension | uWebSockets.js (C++ Core) | Centrifugo (Go Standalone Server) | Socket.IO (with Redis Adapter) |
|---|---|---|---|
| Underlying Engine | C++ LibUV bindings | Go Goroutines | Node.js JavaScript (ws) |
| RAM per 100k Sockets | ~180 MB (Lowest Footprint) | ~350 MB | ~1.4 GB (Heavy objects) |
| Max Scale per Instance | ~250,000 connections/node | ~200,000 connections/node | ~40,000 connections/node |
| Pub/Sub Backplane | Redis / NATS adapter | Native Built-in Redis/NATS | @socket.io/redis-adapter |
| Best For | Ultra-high performance custom APIs | Turnkey real-time server (Decoupled) | Traditional Node.js monoliths |
3. High-Throughput Cluster Execution with uWebSockets.js & Redis PubSub
uWebSockets.js runs C++ networking directly inside Node.js, achieving 8x lower latency and 10x higher concurrency than standard Node.js ws:
// server/websocketServer.ts
import uWS from "uWebSockets.js";
import { createClient } from "redis";
const redisPublisher = createClient({ url: "redis://redis-cluster.internal:6379" });
const redisSubscriber = redisPublisher.duplicate();
await redisPublisher.connect();
await redisSubscriber.connect();
const app = uWS.App();
// 1. Subscribe to Global Redis Backplane for Cross-Server Broadcasts
redisSubscriber.pSubscribe("room:*", (message, channel) => {
const roomName = channel.replace("room:", "");
// Broadcast to all local clients in this room!
app.publish(roomName, message);
});
// 2. Configure uWebSockets Endpoint
app.ws("/ws", {
compression: uWS.DEDICATED_COMPRESSOR_3KB,
maxPayloadLength: 16 * 1024, // 16 KB max message
idleTimeout: 120, // 2-minute keep-alive timeout
open: (ws) => {
console.log("Client connected. Total local connections incremented.");
},
message: (ws, message, isBinary) => {
const data = JSON.parse(Buffer.from(message).toString());
if (data.action === "JOIN_ROOM") {
ws.subscribe(data.room); // Native C++ room subscription!
}
if (data.action === "SEND_MESSAGE") {
// Publish to Redis Backplane so ALL 5 server pods receive it!
redisPublisher.publish(`room:${data.room}`, JSON.stringify(data.payload));
}
},
close: (ws, code, message) => {
console.log("Client disconnected cleanly.");
},
});
app.listen(9001, (token) => {
if (token) console.log("uWebSockets server listening on port 9001");
});4. Centrifugo: The Turnkey Real-Time Messaging Server
For engineering organizations that prefer not to write and maintain custom WebSocket connection infrastructure in application code, Centrifugo acts as a standalone, production-ready real-time proxy:
- JWT Client Authentication: Clients authenticate via short-lived JWTs signed by your main backend API.
- Native History & Presence: Built-in support for chat message history and "Who is online" member lists.
- Universal Transport: Supports WebSockets, HTTP-streaming, and Server-Sent Events (SSE) with automatic fallback.
[Browser Client] ---> [Centrifugo Server (Go)] <===(Redis)===> [Centrifugo Server 2]
^
| (HTTP POST /api/publish: Backend emits event!)
[Your Python/Rails/Node API Backend]5. Linux Kernel Tuning for 1,000,000 Open TCP Sockets
By default, Linux kernels are configured for general-purpose workloads, capping connections at 1,024 file descriptors.
To support 1,000,000 concurrent sockets on Ubuntu/Debian server nodes, apply the following sysctl.conf and limits.conf parameters:
1. Increase OS File Descriptors (/etc/security/limits.conf):
# /etc/security/limits.conf
* soft nofile 2097152
* hard nofile 2097152
root soft nofile 2097152
root hard nofile 20971522. Kernel TCP Networking Tuning (/etc/sysctl.conf):
# /etc/sysctl.conf
# Maximum open file handles system-wide
fs.file-max = 2097152
# Increase TCP connection backlog queue (Prevents dropped SYN packets)
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# Expand ephemeral port range for outgoing connections
net.ipv4.ip_local_port_range = 1024 65535
# Optimize TCP Memory Buffers (Reduce RAM per idle connection!)
# (min, default, max buffer sizes in bytes: 4KB / 8KB / 16KB)
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# Enable TCP Fast Open & Window Scaling
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_window_scaling = 1
# Reduce TIME_WAIT duration for faster socket recycling
net.ipv4.tcp_fin_timeout = 15Apply immediately:
sudo sysctl -p6. Performance Benchmarks: Memory Footprint at 500,000 Sockets
+-------------------------------------------------------------+
| RAM Consumption for 500k Active Sockets (GB) |
+-------------------------------------------------------------+
Standard Socket.IO on Node.js `ws` | ==================================== [28.4 GB]
Centrifugo (Go Engine) | ============ [3.8 GB]
uWebSockets.js (C++ Engine) | ====== [1.9 GB] (15x Less Memory!)
+-------------------------------------+
0GB 10GB 20GB 30GB| Metric | Standard Node ws / Socket.IO | uWebSockets.js + Redis Cluster |
|---|---|---|
| Max Sockets / Node (32GB RAM) | ~50,000 connections | ~350,000 connections |
| Broadcast Latency (p99) | 120 ms | 3.2 ms |
| Memory per Idle Connection | ~55 KB | ~3.8 KB |
| Cross-Server Cluster Sync | Heavy JSON serializing | Binary Redis / NATS Pub/Sub |
7. Scaling WebSockets: Checklist
+-----------------------------------------------------------------------------------------+
| 1,000,000 WebSocket Engineering Checklist |
+-----------------------------------------------------------------------------------------+
| [✓] C++ / GO NETWORKING: Deploy uWebSockets.js or Centrifugo for low memory per socket. |
| [✓] CLUSTER BACKPLANE: Use Redis Cluster or NATS for sub-5ms cross-server broadcasting. |
| [✓] KERNEL FILE LIMITS: Configure 'nofile = 2,097,152' in /etc/security/limits.conf. |
| [✓] TCP BUFFER TUNING: Restrict 'tcp_rmem' to prevent memory explosion on 1M sockets. |
| [✓] TLS OFFLOADING: Terminate HTTPS/WSS at the Network Load Balancer (NLB) layer. |
| [✓] HEARTBEAT PING/PONG: Enforce 60-second ping/pong cycles to evict dead mobile sockets.|
+-----------------------------------------------------------------------------------------+Conclusion: Engineering Real-Time Systems at Hyperscale
Scaling WebSockets to one million concurrent connections is an exercise in kernel efficiency, memory footprint optimization, and distributed messaging backplanes.
By adopting uWebSockets.js or Centrifugo for ultra-lean connection management, clustering servers with a Redis or NATS Pub/Sub backplane, and applying Linux kernel TCP socket tuning, engineering teams deliver real-time collaborative applications that effortlessly sustain massive concurrent audiences with sub-10ms global delivery.
At MojoStudio, our real-time systems architects design 1M+ connection WebSocket clusters, live trading infrastructure, interactive gaming backends, and low-latency Centrifugo deployments. Contact our team to architect your real-time infrastructure today.
Frequently Asked Questions
1. Why is scaling WebSockets harder than scaling HTTP APIs?
HTTP APIs are stateless and transient: connections open for milliseconds and close. WebSockets maintain persistent, stateful TCP socket connections for millions of users simultaneously, requiring persistent server memory, open file descriptors, and inter-server broadcast coordination.
2. What is a WebSocket Pub/Sub Backplane?
A Pub/Sub backplane (such as Redis Cluster or NATS) is a distributed message bus connecting all WebSocket server pods. When a user sends a message to Pod A, Pod A publishes the message to the backplane so Pod B can broadcast it to users connected on other servers.
3. Why is uWebSockets.js faster than standard Node.js ws?
uWebSockets.js is written in compiled C++ using lightweight event-driven LibUV bindings, bypassing the heavy V8 JavaScript object allocation overhead and consuming up to 15x less RAM per open socket.
4. What is Centrifugo?
Centrifugo is an open-source, scalable real-time messaging server written in Go that handles client WebSocket connections, JWT authentication, and channel broadcasting out of the box, decoupling real-time infrastructure from application code.
5. What Linux kernel setting limits concurrent WebSocket connections?
The ulimit -n (file descriptor limit) and fs.file-max kernel parameters dictate the maximum number of open sockets a server can maintain. For 1M connections, these must be increased to over 2,000,000.
6. How much RAM is needed for 1,000,000 WebSocket connections?
Using tuned C++ engines (uWebSockets.js) and optimized TCP buffers (tcp_rmem), 1M idle connections consume approximately 4GB to 8GB of RAM. Unoptimized Node.js implementations can consume over 60GB of RAM.
7. What is the role of TLS Offloading in WebSocket architectures?
Terminating TLS (SSL) at the Network Load Balancer (NLB) or Cloudflare edge removes the heavy CPU encryption handshake burden from the application WebSocket pods, allowing pods to focus 100% of CPU on message routing.
8. How do WebSocket heartbeats prevent "Ghost" connections?
Heartbeats (periodic Ping/Pong frames) verify that the client connection is still physically alive. If a mobile device loses cellular reception without closing the TCP socket, the server automatically evicts the ghost socket after a timeout.
9. When should you use NATS instead of Redis for a WebSocket backplane?
NATS is preferred for ultra-high throughput (millions of messages per second) with clustered multi-region replication and lower memory footprint compared to Redis Pub/Sub.
10. How does MojoStudio help companies scale WebSockets?
MojoStudio engineers custom uWebSockets.js clusters, Centrifugo real-time deployments, Redis/NATS backplanes, and Linux kernel performance tunings. Explore our Backend & Web Services to learn more.
Frequently Asked Questions
HTTP APIs are stateless and transient: connections open for milliseconds and close. WebSockets maintain persistent, stateful TCP socket connections for millions of users simultaneously, requiring persistent server memory, open file descriptors, and inter-server broadcast coordination.