1. Background
Plenty of messaging systems implement publish-subscribe — Kafka, RabbitMQ, ActiveMQ are the big names. Lighter options include Guava’s EventBus and Redis pub/sub. The MQ heavyweights get plenty of coverage elsewhere, so this post focuses on how Redis handles pub/sub under the hood. In production, Redis pub/sub sees limited adoption for two reasons. First, delivery guarantees are weak: if the network drops, in-flight messages are gone with no recovery. Second, Redis runs pub/sub through a single-threaded event loop, so a message burst can bloat the output buffer and even crash the server. That said, when data safety isn’t critical, Redis pub/sub is hard to beat for simplicity.
2. Basic Operations
Redis pub/sub covers four operations: subscribe, unsubscribe, pattern subscribe, and pattern unsubscribe. Here’s how they work in practice:
Start the Redis server (Windows example):
1
2
3C:\Tools\Redis>redis-server.exe redis.windows.conf
...
The server is now ready to accept connections on port 6379Create client
client1and subscribe to channelchannel1:1
2
3
4
5
6redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> SUBSCRIBE channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1Create client
client2and subscribe to channelchannel2:1
2
3
4
5
6redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> SUBSCRIBE channel2
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel2"
3) (integer) 1Create client
client3and pattern-subscribe tochannel*:1
2
3
4
5
6redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> PSUBSCRIBE channel*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "channel*"
3) (integer) 1Publish a message to channel
channel2:1
2
3
4redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> PUBLISH channel2 "msg from channel2"
(integer) 2
127.0.0.1:6379>Both
client2andclient3receive the message:1
2
3
4
5
6
7
8
9
10# ----------client2---------
1) "message"
2) "channel2"
3) "msg from channel2"
# ----------client3---------
1) "pmessage"
2) "channel*"
3) "channel2"
4) "msg from channel2"
Here we can see that publishers and subscribers connect through channels. Regular subscriptions use exact matching; pattern subscriptions use glob-style matching. The structure maps to this use case diagram:
3. Under the Hood
The core pub/sub implementation lives in pubsub.c. The relevant function declarations are visible in the server.h header:
1 | void subscribeCommand(client *c); /* regular subscribe */ |
- Regular subscription flow:
1 |
|
The regular subscription does two things: it adds the channel to the client’s pubsub_channels dict, and it registers the client in the server’s pubsub_channels dict. The structure looks like this: