Pub/Sub Patterns
While Redis Streams are great for durable logs, sometimes you just need speed. You want to broadcast a notification to 1,000 connected clients instantly, and you don’t care if they miss it while offline. This is where Pub/Sub shines.
Pub/Sub (Publish/Subscribe) is a messaging pattern where senders (publishers) do not program messages to be sent directly to specific receivers (subscribers). Instead, messages are published to abstract “channels”.
1. Fire-and-Forget
The most defining characteristic of Redis Pub/Sub is that it is ephemeral.
- No Persistence: If a subscriber is offline, they will never receive the message.
- Zero Storage: Redis does not store the message. It simply pushes it to all connected sockets and discards it.
- Speed: Without disk I/O, Pub/Sub offers microsecond latency.
2. Commands
Basic Messaging
# Client 1: Subscribe to a channel
SUBSCRIBE news
# Client 2: Publish to that channel
PUBLISH news "Breaking News: Redis is fast!"
# Returns: (integer) 1 (number of clients that received it)
Pattern Matching (PSUBSCRIBE)
You can also subscribe to patterns using glob-style wildcards.
# Listen to all user updates
PSUBSCRIBE user:*:update
3. Interactive: Broadcasting
Visualize how a single message is instantly broadcast to all active subscribers.
4. Pub/Sub vs. Streams
When should you use which?
| Feature | Pub/Sub | Streams |
|---|---|---|
| Persistence | None (Fire-and-Forget) | Disk-backed (AOF/RDB) |
| History | No | Yes (Infinite Log) |
| Delivery Guarantee | At-most-once | At-least-once (with Consumer Groups) |
| Fan-out | Yes (All subscribers get it) | Yes (Multiple Consumer Groups) |
| Use Case | Real-time chat, Live notifications | Event Sourcing, Job Queues, Audit Logs |
5. Code Examples: Chat Room
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
func main() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
// Subscriber
pubsub := rdb.Subscribe(ctx, "news")
defer pubsub.Close()
// Go channel to receive messages
ch := pubsub.Channel()
go func() {
for msg := range ch {
fmt.Println("Received:", msg.Payload)
}
}()
// Publisher
rdb.Publish(ctx, "news", "Hello World!")
// Block to keep main alive for demo
select {}
}
6. Summary
Pub/Sub is the tool of choice for live, ephemeral data. It complements Streams perfectly: use Streams for data you can’t afford to lose, and Pub/Sub for data that needs to be everywhere, instantly.