Publish and subscribe (pub/sub) is a message communication model. The main purpose is to decouple the coupling between message publishers and message subscribers. This Point is similar to the Observer pattern in design patterns. pub/sub not only solves the direct code-level coupling of publishers and subscribers, but also solves the coupling of the two in physical deployment. As a pub/sub server, redis plays a message routing function between subscribers and publishers. Subscribers can subscribe to the redis server for the message types they are interested in through the subscribe and psubscribe commands. Redis calls the message type a channel. When the publisher sends a specific type of message to the redis server through the publish command. All clients that subscribe to this message type will receive this message. The message delivery here is many-to-many. A client can subscribe to multiple channels and send messages to multiple channels.
Let’s start with the basic commands:
PSUBSCRIBE pattern [pattern ...] #订阅一个或多个符合给定模式的频道;PUBSUB subcommand [argument [argument ...]] #查看订阅与发布系统状态;PUBLISH channel message #将信息发送到指定的频道;PUNSUBSCRIBE [pattern [pattern ...]] #退订所有给定模式的频道;SUBSCRIBE channel [channel ...] #订阅给定的一个或多个频道的信息;UNSUBSCRIBE [channel [channel ...]] #指退订给定的频道;
As you can see from the redis manual, in fact, the "publish and subscribe" mode only has 6 commands. Let me explain them one by one.
SUBSCRIBE
Subscribe to information from a given channel or channels.
SUBSCRIBE channel [channel ...]
Judging from the official explanation above, its gameplay is a bit like listening to the radio in real life. What do we have to do if we want to listen to the radio? It must be FM. Only on the correct channel can we listen to good programs. So to subscribe, we must first subscribe to a channel. Let me give an example below. Open two clients and subscribe to the msg channel respectively. For example, as follows:
root@localhost:~ # redis-cli -p 6379127.0.0.1:6379> SUBSCRIBE msg Reading messages... (press Ctrl-C to quit) 1) "subscribe"2) "msg"3) (integer) 1 root@localhost:~ # redis-cli -p 6379127.0.0.1:6379> SUBSCRIBE msg Reading messages... (press Ctrl-C to quit) 1) "subscribe"2) "msg"3) (integer) 1
SUBSCRIBE can also subscribe to multiple channels, so that the information it receives may come from multiple channels.
PUBLISH
Up to now, these two subscibes are monitoring the msg channel. Next, if there is news coming out of the msg channel, it will definitely be subscribed. Received, let's first look at how to use this command in the redis manual.
Send information message to the specified channel channel.
PUBLISH channel message
The following demonstration:
See, after publish sends a message on the msg channel, it is monitored by subscribe, and then printed separately. Output, okay, so far, the most basic publish-subscribe model is like this. Isn’t it very simple? Actually? ? ? It's that simple, but sometimes we still have a need, that is, can I fuzzy match the key? For example, it is required to subscribe to all channels with the prefix china. If this can be done, it would be really awesome. . . If I were to answer, it would certainly be that the mighty Redis can definitely do it, it provides the command PSUBSCRIBE.
PSUBSCRIBE
Subscribe to one or more channels that match the given pattern. Each pattern uses as the matching character. For example, it matches all channels ending with Channels starting with it (it.news, it.blog, it.tweets, etc.), news.* matches all channels starting with news. (news.it, news.global.today, etc.), and so on.
PSUBSCRIBE pattern [pattern ...]
After seeing the above explanation, you may be thinking, isn’t this just regular matching? . . Next, I will subscribe to all channels with "china" as the prefix, because the prefix "P" stands for "Pattern", right? .
PSUBSCRIBE can receive multiple parameters to match different patterns. After reading a small example, you should have a perceptual understanding of the pub/sub function. It should be noted that when a connection passes through the subscribe or psubscribe subscription channel, it enters the subscription mode. In this mode, no other commands can be sent except subscribing to additional channels or exiting subscription mode with the unsubscribe or punsubscribe command. In addition, use the psubscribe command to subscribe to multiple wildcard channels. If a message matches multiple channel patterns, the same message will be received multiple times.
Although the pub/sub implementation of Redis only requires 150 lines of code, its functions may not be complete enough. There is not much support in terms of security, authentication, and reliability.
When a client sends information to subscribers through the PUBLISH command, we call the client a publisher.
When a client uses the SUBSCRIBE or PSUBSCRIBE command to receive information, we call the client a subscriber.
In order to decouple the relationship between publisher and subscriber, Redis uses channel as the intermediary between the two - the publisher publishes information directly to the channel, The channel is responsible for sending information to the appropriate subscribers. There is no mutual relationship between the publisher and the subscriber, and they do not know the existence of each other:
知道了发布和订阅的机制之后,接下来就可以开始研究具体的实现了,我们从Redis的订阅命令开始说起。
前面说到,Redis将所有接受和发送信息的任务交给channel来进行,而所有channel的信息就储存在redisServer这个结构中:
struct redisServer { // 省略 ... dict *pubsub_channels; // Map channels to list of subscribed clients // 省略 ... };
pubsub_channels是一个字典,字典的键就是一个个channel,而字典的值则是一个链表,链表中保存了所有订阅这个channel的客户端。
举个例子,如果在一个 redisServer 实例中,有一个叫做 news 的频道,这个频道同时被client_123 和 client_456 两个客户端订阅,那么这个 redisServer 结构看起来应该是这样子:
可以看出,实现SUBSCRIBE命令的关键,就是将客户端添加到给定channel的订阅链表中。
除了直接订阅给定channel外,还可以使用PSUBSCRIBE订阅一个模式(pattern),订阅一个模式等同于订阅所有匹配这个模式的channel 。
和redisServer.pubsub_channels属性类似,redisServer.pubsub_patterns属性用于保存所有被订阅的模式,和pubsub_channels不同的是, pubsub_patterns是一个链表(而不是字典):
struct redisServer { // 省略 ... list *pubsub_patterns; // A list of pubsub_patterns // 省略 ... };
pubsub_patterns 的每一个节点都是一个 pubsubPattern 结构的实例,它保存了被订阅的模式,以及订阅这个模式的客户客户端:
typedef struct pubsubPattern { redisClient *client; robj *pattern; } pubsubPattern;
举个例子,假设在一个 redisServer 实例中,有一个叫做 news.* 的模式同时被客户端client_789 和 client_999 订阅,那么这个 redisServer 结构看起来应该是这样子:
现在可以知道,实现PSUBSCRIBE命令的关键,就是将客户端和订阅的模式添加到redisServer.pubsub_patterns当中。
The above is the detailed content of Redis publish/subscribe model example analysis. For more information, please follow other related articles on the PHP Chinese website!