12/04/2026 18:17pm

EP.86 Managing WebSocket Connections Using Redis Pub/Sub
#Redis Pub/Sub
#Redis
#WebSocket
#Golang
#Go
As real-time applications grow and user numbers increase, running a single WebSocket server may no longer be sufficient. This creates the need to scale out your WebSocket infrastructure using multiple instances (multi-instance setup) to handle a larger load.
In this episode, we’ll walk you through how to use Redis Pub/Sub to synchronize communication across multiple WebSocket server instances — so that users connected to any server can still send and receive messages in real time.
🔄 Why Use Redis Pub/Sub?
Typically, a WebSocket server only holds connections of the clients that are directly connected to it.
When multiple instances are running, a client connected to Server A won’t be able to send messages to clients on Server B — unless we bridge the communication between servers.
Redis Pub/Sub solves this challenge by acting as a message broker between WebSocket server instances:
| Role | Description |
|---|---|
| Publisher | When a client sends a message to a WebSocket server, that server publishes the message to a Redis channel. |
| Subscriber | All WebSocket server instances subscribe to the same Redis channel and broadcast received messages to their connected clients. |
✅ Result:
- All users receive the same messages regardless of which server they are connected to.
- The system is ready for horizontal scaling with ease.
🧪 Example: Go + Redis Pub/Sub
package main
import (
"context"
"fmt"
"log"
"net/http"
"github.com/go-redis/redis/v8"
"github.com/gorilla/websocket"
)
var (
upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
clients = make(map[*websocket.Conn]bool)
ctx = context.Background()
)
func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
go subscribeRedis(rdb)
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Upgrade error:", err)
return
}
defer conn.Close()
clients[conn] = true
for {
_, msg, err := conn.ReadMessage()
if err != nil {
log.Println("ReadMessage error:", err)
delete(clients, conn)
break
}
// Publish message to Redis
if err := rdb.Publish(ctx, "chat_channel", msg).Err(); err != nil {
log.Println("Publish error:", err)
}
}
})
log.Println("WebSocket server started on :8080")
http.ListenAndServe(":8080", nil)
}
func subscribeRedis(rdb *redis.Client) {
sub := rdb.Subscribe(ctx, "chat_channel")
ch := sub.Channel()
for msg := range ch {
for client := range clients {
if err := client.WriteMessage(websocket.TextMessage, []byte(msg.Payload)); err != nil {
log.Println("WriteMessage error:", err)
client.Close()
delete(clients, client)
}
}
}
}
🔍 Code Explanation
| Section | Description |
|---|---|
clients map | Tracks WebSocket connections for clients connected to the current instance |
rdb.Publish | Sends a message to the Redis channel when a client sends data |
subscribeRedis() | Listens to Redis channel and forwards incoming messages to connected clients |
💡 Benefits of Using Redis Pub/Sub
✅ Supports multi-instance WebSocket servers
✅ Enables easy horizontal scaling
✅ Handles high user loads without losing message integrity
✅ Instances don’t need to know about each other directly
🚀 Challenge: Try It Yourself!
- Launch multiple WebSocket server instances (e.g., multiple processes or containers)
- Use Redis Pub/Sub as a central message broker
- Test cross-server communication: clients connected to different servers should still receive messages from each other
🔜 Next EP:
EP.87: Securing WebSocket Servers Against DDoS Attacks
We’ll explore how to protect your WebSocket infrastructure from threats like DDoS, connection flooding, and malformed frame attacks, ensuring your real-time system is production ready.
Read more
🔵 Facebook: Superdev Academy
🔴 YouTube: Superdev Academy
📸 Instagram: Superdev Academy
🎬 TikTok: https://www.tiktok.com/@superdevacademy?lang=th-TH
🌐 Website: https://www.superdevacademy.com/en