tft每日頭條

 > 生活

 > redis訂閱用途

redis訂閱用途

生活 更新时间:2025-03-07 09:11:40

redis發布/訂閱應用

這一篇我們來看看Redis好玩的發布訂閱模式,其實在很多的MQ産品中都存在這樣的一個模式,我們常聽到的一個例子就是郵件訂閱的場景,什麼意思呢,也就是說100個人訂閱了你的博客,如果博主發表了文章,那麼100個人就會同時收到通知郵件,除了這個場景還能找到其他場景麼,當然有啦,你想想,如果你要在内存裡面做一個讀寫分離的程序,為了維持數據的完整性,你是不是需要保證在寫入的時候,也要分發到各個讀内存的程序中呢?所以說場景還是很多的,在于你的挖掘~~~

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

看到麼有,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 ...]

看到上面的解釋,你心裡可能就在想,這不就是正則匹配麼。。。而且前綴”P”就是Pattern的意思,對吧,接下來我就訂閱一下所有china為前綴的channel。

redis訂閱用途(細述Redis發布訂閱模式學習)1

當然,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發布訂閱模式學習)2

知道了發布和訂閱的機制之後,接下來就可以開始研究具體的實現了,我們從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訂閱用途(細述Redis發布訂閱模式學習)3

可以看出,實現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訂閱用途(細述Redis發布訂閱模式學習)4

現在可以知道,實現PSUBSCRIBE命令的關鍵,就是将客戶端和訂閱的模式添加到redisServer.pubsub_patterns當中。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved