“Brother 65, if you made a beautiful lady as your girlfriend, how would you spread the news to your WeChat friends?”

“Then don’t take some beautiful photos of your girlfriend + intimate photos, get a Jiugongge graphic message and post it in the circle of friends to hype it up and attack the single dog.”

Like this scenario where Brother 65 publishes news through the circle of friends, and friends who follow Brother 65 can receive notifications is called a “publish/subscribe mechanism”.

Today, I won’t talk about Miss Sister, let’s have a deep understanding of “Redis publish/subscribe mechanism”. principles and practical application.

Redis via SUBSCRIBE,UNSUBSCRIBEandPUBLISH To implement the publish-subscribe messaging mode, Redis provides two mode implementations, namely “publish/subscribe to channel” and “publish/subscribe to mode”.

[toc]

Introduction to Redis publish and subscribe

Redis publish-subscribe (Pus/Sub) is a message communication mode: the sender PUBLISHPublish messages, subscribers pass SUBSCRIBE Subscribe to receive messages or viaUNSUBSCRIBE unsubscribe.

It mainly consists of three parts: “Publisher”, “Subscriber”, “Channel”.

Publishers and subscribers belong to the client, Channel is the Redis server, publishers publish messages to channels, and subscribers who subscribe to this channel receive messages.

As shown in the figure below, three “subscribers” subscribe to the “ChannelA” channel:

subscription

At this time, the team leader publishes a message to “ChannelA”, and the subscribers of this message will receive the message “Follow Code Byte, Improve Technology”:

Publish/Subscribe

Pub/Sub in action

Not much nonsense, after knowing the basic concepts, the first step in learning a technology is to run it, and then to explore the principle, so as to achieve the state of “knowing the truth and knowing the reason”.

There are two modes to implement “publish/subscribe”:

  • Publish and subscribe using channels;
  • Publish and subscribe using patterns.

It should be noted that the publish-subscribe mechanism has nothing to do with db space. For example, when publishing on db 10, the subscribers of db0 will also receive messages.

Implemented by channel (Channel)

Three steps:

  1. Subscribers subscribe to channels;
  2. The publisher publishes a message to the “Channel”;
  3. All subscriptions “channel” subscribers received the message.

Subscribers subscribe to channels

use SUBSCRIBE channel [channel ...]Subscribe to one or more channels, O(n) time complexity, n = number of subscribed Channels.

SUBSCRIBE develop
Reading messages... (press Ctrl-C to quit)
1) "subscribe" // 消息类型
2) "develop" // 频道
3) (integer) 1 // 消息内容

After executing this command, the client enters the subscription state, and the subscriber can only use thesubscribe,unsubscribe,psubscribeandpunsubscribeThese four are “publish/subscribe” directives.

The client “Xiao Caiji” subscribes to the “develop” channel to receive messages from the group leader, and the message response body indicates:

  • Message type: subscribe, message, unsubscribe
  • channel
  • Message content: It has different meanings depending on the message type.

After entering the subscription, the client can receive 3 types of message replies:

  1. subscribe: Feedback message of successful subscription, the second value is the channel name of the successful subscription, and the third value is the number of channels subscribed by the current client.
  2. message: The client receives the message, the second value indicates the name of the channel that generated the message, and the third value is the content of the message.
  3. unsubscribe: Indicates that a channel has been successfully unsubscribed. The second value is the corresponding channel name, and the third value is the number of channels subscribed by the current client. When this value is 0, the client will exit the subscription state, and then other commands that are not in the “pub/sub” mode can be executed. .

Publisher publishes message

Team leader use PUBLISH channel message Post a message to the specified “develop” channel.

PUBLISH develop 'do job'
(integer) 1

It should be noted that the publishedThe message is not persistent. If there is a new “development” pretty boy subscribed after the message is published, it can only receive subsequent messages published to the channel.

A good one “Don’t ask about the past, just strive for the present”.

Subscriber accepts messages

Subscribers who follow the “develop” channel will receive a “do job” message.

// 订阅 develop 频道
SUBSCRIBE develop
Reading messages... (press Ctrl-C to quit)
1) "subscribe" // 订阅频道成功
2) "develop" // 频道
3) (integer) 1
// 当发布者发布消息,订阅者读取到的消息如下
1) "message" // 接受到消息
2) "develop" // 频道名称
3) "do job" // 消息内容

unsubscribe channel

The reverse operation of the subscription, “Brother 65” shows his affection in the circle of friends every day. He can’t stand it anymore, so he unsubscribes from his circle of friends.

Using the UNSUBSCRIBE command to unsubscribe from the specified “mode” will not affect the channels subscribed to by the `subscribe command.

same unsubscribecommand also does not affect thepsubscribeRules for command subscriptions.

Implemented by pattern (Pattern)

Next, let’s look at another way to implement publish and subscribe. The following figure shows that when the “matching pattern” matches this channel, when the message publishes a message to the channel, the message will also be published to the “pattern” that matches the channel. Subscribe to this Clients of the schema will also receive the message.

smile.girl.* The pattern represents the “You are beautiful when you smile” pattern, and the two channels that match this pattern are smile.girls.Tina,smile.girls.maggi respectively expressing fans who like “Smiling Tina” and “Smiling maggi”.

As shown below:

pattern matching

Now Tina posts a message and sends a message to smile.girls.Tinachannel, in addition to subscribing smile.girls.Tina In addition to the message received by fans of this channel, this message is also sent to subscribers smile.girl.* Fans of the pattern (because the channel matches the pattern).

These fans are more greedy, and all the “girls who are beautiful when they smile” are paying attention. LSP~~, Brother Code is not such a person.

pattern matching publish

To use a match pattern, use PUBLISH Publish message to subscription smile.girls.Tina In addition to the client, the “channel” will be compared with the pattern in the “pub/sub pattern”, and if the Channel matches a pattern, the message will also be published to clients subscribed to this pattern.

subscription model

The command for subscribe mode isPSUBSCRIBEthe following indicates that the LSP subscribes to the “smile.girl.*” mode:

PSUBSCRIBE smile.girls.*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe" // 消息类型
2) "smile.girls.*"// 模式
3) (integer) 1 //订阅数

The corresponding reverse cancel mode subscription command isPUNSUBSCRIBE smile.girl.*.

Subscribe to the channel “smile.girls.Tina”:

SUBSCRIBE smile.girls.Tina
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "smile.girls.Tina"
3) (integer) 1

Subscribe to the channel “smile.girls.maggi”:

SUBSCRIBE smile.girls.maggi
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "smile.girls.maggi"
3) (integer) 1

Tina posted a message, **followed by “smile.girls.Tina”** and fans who subscribed to the “smile.girls.*” mode matching the channel received the message.

Fans who follow the “smile.girls.*” mode receive a message

PSUBSCRIBE smile.girls.*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "smile.girls.*"
3) (integer) 1
//进入订阅状态,接收到消息
1) "pmessage" 消息类型
2) "smile.girls.*"
3) "smile.girls.Tina"
4) "love u" // 消息内容

Fans who follow “smile.girls.Tina” receive a message

127.0.0.1:6379> SUBSCRIBE smile.girls.Tina
Reading messages... (press Ctrl-C to quit)
// 订阅成功
1) "subscribe"
2) "smile.girls.Tina"
3) (integer) 1
// 接收消息
1) "message"
2) "smile.girls.Tina"
3) "love u"

have to be aware of is,If a client subscribes to a pattern and channel that matches the pattern, the client will receive the message multiple times.

For example, Brother 65 subscribes to the channel “smile.girls.Tina” and the mode of “smile.girls.*”, then when Tina posts news to the channel, Brother 65 will receive two ticket messages, one message type ismessagea type ispmessage.

Redisson and SpringBoot in action

Official documentation: https://github.com/redisson/redisson/wiki/6.-distributed-objects/#67-topic

producer code

/**
 * 发布消息到 Topic
 * @param message 消息
 * @return 接收消息的客户端数量
 */
public long sendMessage(String message) {
    RTopic topic = redissonClient.getTopic(CHANNEL);
    long publish = topic.publish(message);
    log.info("生产者发送消息成功,msg = {}", message);
    return publish;
}

consumer code

public void onMessage() {
  // in other thread or JVM
  RTopic topic = redissonClient.getTopic(CHANNEL);
  topic.addListener(String.class, (channel, msg) -> {
    log.info("channel: {} 收到消息 {}.",  channel, msg);
  });
}

It should be noted that publishing messages and listening messages must run in different JVMs. If the same JVM is used redissonClient If you publish it, you will not listen to your own messages.

Principle analysis

We know the concept of publish and subscribe through the above, and there are two modes to realize publish and subscribe. And use native instructions and Redisson for actual combat.

Next, we need to deeply understand how Redis implements the publish and subscribe mechanism, so that we know what it is and why it is.

How is the publish/subscribe of channel (Channel) implemented?

65 Brother, what data structure would you use to locate the corresponding client based on the channel?

Brother code, I think it can be implemented with a dictionary. The key of the dictionary corresponds to the channel being subscribed to, and the value of the dictionary can be a linked list, which stores all the clients subscribed to this channel.

data structure

Smart, Redis uses redis.hone of redisServer The structure maintains each server process to represent the server state,pubsub_channels Properties is a dictionary that holds information about subscribed channels.

struct redisServer {
  ...
  /* Pubsub */
   dict *pubsub_channels;
  ...
}

As shown in the figure below, “Mage” and “Liangzai” subscribed to “redis-channel”, and “Otaku” and “LSP” subscribed to “Zhi~Teng¥Y*xiang-ri”:

Channel subscription and publishing principle

send message to channel

Producer call PUBLISH channel messsage To send a message, the program first starts from the channel pubsub_channels Locate the bucket where the key of the dictionary is located, and then send the message to all clients in the value list corresponding to this key.

unsubscribe channel

UNSUBSCRIBEThe command can unsubscribe from the specified channel: For the dictionary operation, find the linked list of concerns according to the key, traverse the linked list, and delete the client, so that the message will not be sent to the client.

How is the publish/subscribe pattern implemented?

Next, let’s continue to look at the principle of publish and subscribe based on pattern implementation…

when using PUBLISHWhen publishing a message to a channel, not only all clients subscribed to the channel will receive the message, but clients matching this pattern will also receive the message.

source code in server.h in the fileredisServer.pubsub_patterns property definition.

struct redisServer {
  ...
  /* A dict of pubsub_patterns */
	dict *pubsub_patterns;
  ...
}

It is also a dict dictionary type, the key corresponds to the “pattern” mode, and the value is a linked list type structure: list *clientsIt contains a list of clients matching each pattern.

when executed PSUBSCRIBE smile.girls.*When the command is executed, it will be executedpubsubSubscribePatternmethod.

Here I will share how to locate the key source code, publish and subscribe, and we will search based on experiencepubsubcan be retrieved pubsub.c:

pubsub.c

The Redis source code debugged by CLion is from the same company as IDEA for Java development, so the shortcut keys are the same, and then use Command + F12 Pop-up method search, find pubsubSubscribePattern Subscription mode method.

The method parameters respectively indicate the client client *c that pays attention to the pattern, and the *pattern that the client wants to pay attention to. The main logic of the method is as follows:

  1. listSearchKey(c->pubsub_patterns,pattern): According to the pattern, look up whether the key of the pattern already exists from the redisServer.pubsub_patterns dictionary, and call it if it existsaddReplyPubsubPatSubscribed Notify the client that it has subscribed, otherwise continue to execute the following logic.
  2. dictFind(server.pubsub_patterns,pattern): According to the mode patternfrom dictionary server.pubsub_patternsFind the dictEntry hash bucket, call it if it is empty listCreate()Create a client list list *clientsand put it into a dictionary, key = pattern, value = list *clients linked list.
  3. The hash bucket is not empty, then put the current client client *c add to list *clientsThe tail node of the linked list.

Subscription mode source code

Therefore, the publish and subscribe mode implemented by the mode also uses the dictionary to save the relationship between the mode and the client, as shown in the following figure:

The Principle of Publish-Subscribe Based on Pattern Implementation

when using PUBLISH When publishing messages, in addition to publishing to subscriptionschannelIn addition to the client of the pubsub_patterns Look up the client list in the value corresponding to the key of the matching pattern in the dictionary, and execute the message sending.

Unsubscribe mode

use PUNSUBSCRIBEThe command can unsubscribe from the specified mode. This command performs the reverse operation of the subscription mode: according to the mode, from pubsub_patternsThe client list is found in the dictionary, and the current client is deleted by traversing the list.

Summarize

The Redis publish and subscribe function is mainly implemented through the following commands:

  • subscribe channel [channel ...]: Subscribe to one or more channels;
  • unsubscribe channel unsubscribe from the designated channel;
  • publish channel message Send a message to the specified channel;
  • psubscribe pattern Subscribe to the specified mode;
  • punsubscribe pattern Unsubscribe from the specified mode.

Pub/Sub is database agnostic, such as in DB0 published on DB1Subscribers will also receive.

Publish and subscribe information based on channels is implemented by the server process redisServer.pubsub_channels The dictionary is saved, key = the channel being subscribed to, and value is the linked list of all clients subscribed to the channel.

When a message is published to the channel, iterate over the dictionary to get all clients and send the message to the channel’s clients.

The information of the publish and subscribe based on the schema is stored in the dictionary pubsub_patternskey = pattern, value is the client list.

When a message is published to a channel, in addition to the client subscribed to the channel, all clients subscribed to the pattern matching the channel will also receive the message.

scenes to be used

Having said so much, what scenarios can Redis publish and subscribe in?

Sentinel communication

In the sentinel cluster, each sentinel node uses Pub/Sub to publish and subscribe to realize mutual discovery among sentinels and find slaves. For details, click -> “Sentinel Cluster Principles and Those Things”.

After the sentinel establishes communication with the master, it uses the master to provide a publish/subscribe mechanism in__sentinel__:helloPublish your own information, such as height and weight, whether you are single, IP, port…, and subscribe to this channel to get the information of other sentinels, so as to realize the communication between sentinels.

message queue

Previously, “Code Brother” shared with you how to use Redis List and Stream to implement message queues.

We can also use Redis to publish and subscribe to achieveLightweight and simple MQ functionalityto achieve upstream and downstream decoupling, it should be noted that the messages published and subscribed by Redis will not be persisted, so the newly subscribed clients will not receive historical messages.

It also does not support the ACK mechanism, so the current business cannot tolerate these shortcomings, then use a professional message queue, and if you can tolerate it, you can enjoy the advantages of Redis fast.

Finally, can you call me “Pretty Boy” in the comment area? In order to write this article, Brother Code read a lot of girls who are so beautiful when they smile before writing it. It is not easy to be original.

Friends, like, share, favorite and support me.

References

1. Redis design and implementation

2. https://redisbook.readthedocs.io/en/latest/feature/pubsub.html

#Advanced #Redis #Principle #Application #PublishSubscribe #Mode

Leave a Comment

Your email address will not be published. Required fields are marked *