首頁 >資料庫 >Redis >Redis發布/訂閱模式實例分析

Redis發布/訂閱模式實例分析

WBOY
WBOY轉載
2023-05-27 21:29:321707瀏覽

Redis發布/訂閱應用程式

發布訂閱(pub/sub)是一種訊息通訊模式,主要的目的是解耦訊息發布者和訊息訂閱者之間的耦合,這點和設計模式中的觀察者模式比較相似。 pub /sub不僅僅解決發布者和訂閱者直接程式碼層級耦合也解決兩者在實體部署上的耦合。 redis作為一個pub/sub server,在訂閱者和發布者之間起到了訊息路由的功能。訂閱者可以透過subscribe和psubscribe指令向redis server訂閱自己感興趣的訊息類型,redis將訊息類型稱為通道(channel)。當發布者透過publish指令向redis server傳送特定類型的訊息。訂閱該訊息類型的全部client都會收到此訊息。這裡訊息的傳遞是多對多的。一個client可以訂閱多個 channel,也可以向多個channel發送訊息。

下面還是從基本指令入手:

PSUBSCRIBE pattern [pattern ...]              #订阅一个或多个符合给定模式的频道;PUBSUB subcommand [argument [argument ...]]   #查看订阅与发布系统状态;PUBLISH channel message                       #将信息发送到指定的频道;PUNSUBSCRIBE [pattern [pattern ...]]          #退订所有给定模式的频道;SUBSCRIBE channel [channel ...]               #订阅给定的一个或多个频道的信息;UNSUBSCRIBE [channel [channel ...]]           #指退订给定的频道;

從redis手冊上面可以看到,其實「發佈、訂閱」模式才區區6個指令,下面聽我一一解說下

SUBSCRIBE

訂閱給定的一個或多個頻道的資訊。

SUBSCRIBE channel [channel ...]

從上面的官方解釋來看,它的玩法有一點像現實生活中我們聽收音機一個道理,要想聽收音機,我們要做什麼?肯定就是調頻啦,只有在正確的頻道上面,我們才能聽得到好聽的節目,所以說subscribe首先要訂閱一個頻道(channel),下面我舉個例子,開兩個client,分別訂閱著msg這個頻道,例如下面這樣:

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還可以訂閱多個頻道,這樣一來它接收到的訊息就可能來自多個頻道。

PUBLISH

到現在為止,這兩個subscibe都在監視msg這個頻道,接下來,如果msg頻道有消息傳出,必定會被subscribe接收到,我們還是先看看redis手冊上怎麼用這個指令。

將訊息message傳送到指定的頻道channel。

PUBLISH channel message

如下示範:

  Redis發布/訂閱模式實例分析

看到麼有,publish在msg這個頻道上面發送訊息後,被subscribe監視到了,然後就被分別列印輸出了,好了,到目前為止,最基本的發布訂閱模式就是這樣,是不是很簡單哈。其實呢? ? ?也就是這麼簡單吶,但是呢,有時候我們還有這樣一個需求,就是我能不能模糊匹配key呢?舉了例子,就是要求訂閱china為前綴的所有頻道,如果這樣也可以做到的話,那確實是很屌啦。 。 。如果我要回答的話,那當然會說強大的Redis肯定可以做到,它提供了命令 PSUBSCRIBE。

PSUBSCRIBE

訂閱一個或多個符合給定模式的頻道,每個模式以作為匹配符,例如it匹配所有以it開頭的頻道(it.news、it.blog、it.tweets等等),news.*符合所有以news.開頭的頻道(news.it、 news.global.today 等等),諸如此類。

PSUBSCRIBE pattern [pattern ...]

看到上面的解釋,你心裡可能就在想,這不就是正規匹配麼。 。 。接下來,我將訂閱所有以"china"作為前綴的頻道,因為前綴"P"代表著"Pattern"(模式)的意思,對嗎? 。

  Redis發布/訂閱模式實例分析

PSUBSCRIBE可以接收多個參數,以符合不同的模式。看完一個小例子後應該對pub/sub功能有了一個感性的認識,需要注意的是當一個連接通過subscribe或者psubscribe訂閱通道後就進入訂閱模式。在這種模式除了再訂閱額外的通道或用unsubscribe或punsubscribe命令退出訂閱模式,就不能再發送其他指令。另外使用 psubscribe指令訂閱多個通配符通道,如果一個訊息匹配上了多個通道模式的話,會多次收到同一個訊息。

雖然Redis的pub/sub實作只需要150行程式碼,但其功能可能還不夠完善。在安全,認證,可靠性這方便都沒有太多支援。

Redis發布/訂閱機制

當一個客戶端透過 PUBLISH 指令傳送訊息給訂閱者的時候,我們稱這個客戶端為發布者(publisher)。

而當一個客戶端使用 SUBSCRIBE 或 PSUBSCRIBE 指令接收訊息的時候,我們稱這個客戶端為訂閱者(subscriber)。

為了解耦發布者(publisher)和訂閱者(subscriber)之間的關係,Redis 使用了channel (頻道)作為兩者的中介—— 發布者將信息直接發布給channel ,而channel 負責將訊息傳送給適當的訂閱者,發布者和訂閱者之間沒有相互關係,也不知道對方的存在:

  Redis發布/訂閱模式實例分析

知道了发布和订阅的机制之后,接下来就可以开始研究具体的实现了,我们从Redis的订阅命令开始说起。

SUBSCRIBE命令的实现

前面说到,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 结构看起来应该是这样子: Redis發布/訂閱模式實例分析

可以看出,实现SUBSCRIBE命令的关键,就是将客户端添加到给定channel的订阅链表中。

PSUBSCRIBE命令的实现

除了直接订阅给定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 结构看起来应该是这样子: Redis發布/訂閱模式實例分析

现在可以知道,实现PSUBSCRIBE命令的关键,就是将客户端和订阅的模式添加到redisServer.pubsub_patterns当中。

以上是Redis發布/訂閱模式實例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除