Redis发布订阅

 

*Pub/Sub

SUBSCRIBE, UNSUBSCRIBEPUBLISH 实现了 发布/订阅消息范例,发送者 (publishers) 不直接向特定的接收者发送消息 (subscribers),而是发布消息到频道(channel),不关心有没有订阅者。订阅者订阅关注的一个或多个频道(channel),并且只接收他关注的消息,不管发布者是不是存在。发布者和订阅者的解耦提供了更大的伸缩性、更动态的网络拓扑。

例如,为了订阅通道 foo 和 bar ,客户端可以使用通道名字作为参数来调用 SUBSCRIBE 命令:

SUBSCRIBE foo bar

当有客户端发送消息到这些频道时,Redis将会推送传入的消息给所有订阅这些频道的客户端。

正在订阅频道的客户端不应该发送除了订阅或取消订阅以外的命令。订阅和退订操作的执行结果以消息的形式返回,客户端可以读取收到消息的第一个元素来区分收到的是消息类型,还是订阅和退订操作执行结果。订阅客户端能使用的命令是 SUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, PUNSUBSCRIBE, PINGQUIT.

 

*推送消息的格式

消息是带有三个元素的Array repl

第一个元素是消息的类型:

  • subscribe: 表示成功订阅到以第二个返回元素命名的频道。第三个元素表示客户端当前订阅频道总数。

  • unsubscribe: 表示成功退订以第二个返回元素命名的频道。第三个元素表示客户端当前订阅频道总数。当第三个参数为零的时候,表示客户端已退出Pub/Sub状态,不再订阅任何频道,可以发送订阅和退订以外的Redis command。

  • message: 表示收到其它某一个客户端用 PUBLISH 发布的消息,第二个元素是来源频道的名字,第三个参数是消息实际内容。

 

*数据库&作用域

Pub/Sub 和键空间没有关系,在任何层面上都没有交互,跟数据库number也没有关系。

向db10发布消息也能再db1订阅到消息。

如果您要某种范围,请在通道前加上环境名称(测试,生产……)

*Wire protocol example

SUBSCRIBE first second
*3
$9
subscribe
$5
first
:1
*3
$9
subscribe
$6
second
:2

At this point, from another client we issue a PUBLISH operation against the channel named second:

> PUBLISH second Hello

This is what the first client receives:

*3
$7
message
$6
second
$5
Hello

Now the client unsubscribes itself from all the channels using the UNSUBSCRIBE command without additional arguments:

UNSUBSCRIBE
*3
$11
unsubscribe
$6
second
:1
*3
$11
unsubscribe
$5
first
:0

 

*Pattern-matching subscriptions

The Redis Pub/Sub implementation supports pattern matching. Clients may subscribe to glob-style patterns in order to receive all the messages sent to channel names matching a given pattern.

For instance:

PSUBSCRIBE news.*

Will receive all the messages sent to the channel news.art.figurative, news.music.jazz, etc. All the glob-style patterns are valid, so multiple wildcards are supported.

PUNSUBSCRIBE news.*

Will then unsubscribe the client from that pattern. No other subscriptions will be affected by this call.

Messages received as a result of pattern matching are sent in a different format:

  • The type of the message is pmessage: it is a message received as result of a PUBLISH command issued by another client, matching a pattern-matching subscription. The second element is the original pattern matched, the third element is the name of the originating channel, and the last element the actual message payload.

Similarly to SUBSCRIBE and UNSUBSCRIBE, PSUBSCRIBE and PUNSUBSCRIBE commands are acknowledged by the system sending a message of type psubscribe and punsubscribe using the same format as the subscribe and unsubscribe message format.

 

*Messages matching both a pattern and a channel subscription

A client may receive a single message multiple times if it’s subscribed to multiple patterns matching a published message, or if it is subscribed to both patterns and channels matching the message. Like in the following example:

SUBSCRIBE foo
PSUBSCRIBE f*

In the above example, if a message is sent to channel foo, the client will receive two messages: one of type message and one of type pmessage.

 

*The meaning of the subscription count with pattern matching

In subscribe, unsubscribe, psubscribe and punsubscribe message types, the last argument is the count of subscriptions still active. This number is actually the total number of channels and patterns the client is still subscribed to. So the client will exit the Pub/Sub state only when this count drops to zero as a result of unsubscribing from all the channels and patterns.

 

*Programming example

Pieter Noordhuis provided a great example using EventMachine and Redis to create a multi user high performance web chat.

 

*Client library implementation hints

Because all the messages received contain the original subscription causing the message delivery (the channel in the case of message type, and the original pattern in the case of pmessage type) client libraries may bind the original subscription to callbacks (that can be anonymous functions, blocks, function pointers), using a hash table.

When a message is received an O(1) lookup can be done in order to deliver the message to the registered callback.