Redis系列(八):發佈與訂閱

Redis的發佈與訂閱,有點相似於消息隊列,發送者往頻道發送消息,頻道的訂閱者接收消息。java

1. 發佈與訂閱示例

首先,在本機開啓第1個Redis客戶端,執行以下命令訂閱blog.redis頻道:redis

SUBSCRIBE "blog.redis"
複製代碼

而後,在本機開啓第2個Redis客戶端,執行相同的命令訂閱blog.redis頻道:shell

而後,開啓第3個Redis客戶端,執行以下命令往blog.redis頻道發送消息:服務器

PUBLISH blog.redis "redis-in-action-01"
複製代碼

查看客戶端1和客戶端2,分別看到以下信息:微信

3個客戶端與頻道的關係以下圖所示:spa

能夠經過INFO clients命令查看鏈接的客戶端數:設計

2. 訂閱/退訂頻道

2.1 訂閱頻道

Redis的SUBSCRIBE命令用來訂閱頻道,使用方式以下所示:3d

SUBSCRIBE "blog.redis"
複製代碼

若是是訂閱多個頻道,可使用以下所示命令:code

SUBSCRIBE "blog.redis" "blog.rocketmq"
複製代碼

Redis將全部頻道的訂閱關係保存在服務器狀態的pubsub_channels字典裏,字典的鍵是某個被訂閱的頻道,鍵對應的值是1個鏈表,鏈表裏記錄了全部訂閱這個頻道的客戶端。cdn

以上圖爲例,說明客戶端一、客戶端2正在訂閱頻道"blog.redis",客戶端三、客戶端4正在訂閱頻道「blog.rocketmq」。

若是此時有1個客戶端5,執行了以下命令:

SUBSCRIBE "blog.rocketmq" "blog.java"
複製代碼

那麼服務器狀態保存的頻道訂閱關係將變爲以下圖所示:

2.2 退訂頻道

Redis的UNSUBSCRIBE命令用來退訂頻道,使用方式以下所示:

UNSUBSCRIBE "blog.redis"
複製代碼

若是是退訂多個頻道,可使用以下所示命令:

UNSUBSCRIBE "blog.redis" "blog.rocketmq"
複製代碼

假設如今服務器狀態保存的頻道訂閱關係以下圖所示:

若是此時客戶端5,執行了以下命令:

UNSUBSCRIBE "blog.rocketmq" "blog.java"
複製代碼

那麼服務器狀態保存的頻道訂閱關係將變爲以下圖所示:

3. 訂閱/退訂模式

3.1 示例

首先,啓動1個Redis客戶端,執行以下命令訂閱模式「blog.r*」:

PSUBSCRIBE "blog.r*"
複製代碼

而後,啓動另1個Redis客戶端,執行PUBLISH命令往頻道發送消息:

PUBLISH "blog.redis" "redis-in-action-01"

PUBLISH "blog.rocketmq" "rocketmq-in-action-01"

PUBLISH "blog.java" "java-in-action-01"
複製代碼

能夠看到,第1次啓動的客戶端能夠接收到前2條消息,由於頻道"blog.redis"、"blog.rocketmq"匹配模式「blog.r*」:

但頻道"blog.java"不匹配該模式,因此最後1次發送的消息,該客戶端未接收到。

3.2 訂閱模式

Redis的PSUBSCRIBE命令用來訂閱模式,使用方式以下所示:

PSUBSCRIBE "blog.r*"
複製代碼

若是是訂閱多個模式,可使用以下所示命令:

PSUBSCRIBE "blog.r*" "blog.j?va" "blog.j[ae]va"
複製代碼

Redis將全部模式的訂閱關係保存在服務器狀態的pubsub_patterns屬性裏。

pubsub_patterns屬性是1個鏈表,鏈表中的每一個節點是1個pubsub_Pattern結構,這個結構的pattern屬性記錄被訂閱的模式,client屬性記錄訂閱模式的客戶端。

以上圖爲例,說明客戶端1正在訂閱模式"blog.r*,客戶端2正在訂閱模式「blog.j?va」。

若是此時有1個客戶端3,執行了以下命令:

PSUBSCRIBE "blog.j[ae]va"
複製代碼

那麼服務器狀態保存的模式訂閱關係將變爲以下圖所示:

3.3 退訂模式

Redis的PUNSUBSCRIBE命令用來退訂模式,使用方式以下所示:

PUNSUBSCRIBE "blog.r*"
複製代碼

若是是退訂多個模式,可使用以下所示命令:

PUNSUBSCRIBE "blog.j?va" "blog.j[ae]va"
複製代碼

假設如今服務器狀態保存的模式訂閱關係以下圖所示:

若是此時客戶端3,執行了以下命令:

PUNSUBSCRIBE "blog.j[ae]va"
複製代碼

那麼服務器狀態保存的模式訂閱關係將變爲以下圖所示:

4. 發送消息

若是,服務器狀態保存的頻道訂閱關係以下圖所示:

服務器狀態保存的模式訂閱關係以下圖所示:

此時,若是1個Redis客戶端執行了如下PUBLISH命令:

PUBLISH blog.redis "redis-in-action-01"
複製代碼

那麼,服務器會執行如下2個動做:

  1. 將消息"redis-in-action-01"發送給頻道「blog.redis」的全部訂閱者
  2. 將消息"redis-in-action-01"發送給與頻道「blog.redis」相匹配模式的訂閱者

也就是說,消息"redis-in-action-01"不只會發送給頻道「blog.redis」的訂閱者客戶端一、客戶端2,也會發送給與頻道「blog.redis」相匹配的模式「blog.r*」的訂閱者客戶端5。

5. 查看訂閱信息

可使用Redis的PUBSUB命令來查看頻道或者模式的相關信息。

5.1 查看被訂閱的頻道

若是想要查看被訂閱的頻道信息,可使用命令PUBSUB CHANNELS [pattern],其中pattern參數是可選的:

  1. 若是不指定pattern參數,返回服務器當前被訂閱的全部頻道
  2. 若是指定pattern參數,返回服務器被訂閱的頻道中與pattern模式相匹配的頻道

這個命令的實現原理是經過遍歷服務器狀態保存的pubsub_channels字典來實現的。

舉個具體的例子,若是服務器狀態保存的pubsub_channels字典以下所示:

那麼執行命令PUBSUB CHANNELS的返回結果以下所示:

執行命令PUBSUB CHANNELS r*的返回結果以下所示:

5.2 查看頻道的訂閱者數量

若是想要查看頻道的訂閱者數量,可使用命令PUBSUB NUMSUB [channel1 channel2 ... channeln]

這個命令的實現原理是經過遍歷服務器狀態保存的pubsub_channels字典來實現的,頻道對應的訂閱者鏈表的長度就是該頻道的訂閱者數量。

舉個具體的例子,若是服務器狀態保存的pubsub_channels字典以下所示:

那麼執行命令PUBSUB NUMSUB blog.redis blog.rocketmq blog.java的返回結果以下所示:

5.3 查看被訂閱模式的數量

若是想要查看被訂閱模式的數量,可使用命令PUBSUB NUMPAT

這個命令的實現原理是返回服務器狀態保存的pubsub_patterns鏈表的長度。

舉個具體的例子,若是服務器狀態保存的pubsub_patterns鏈表以下所示:

那麼執行命令PUBSUB NUMPAT的返回結果以下所示:

6. 總結

Redis的發佈與訂閱有點相似於消息隊列的發佈與訂閱,主要包含如下7個命令:

  1. SUBSCRIBE
  2. UNSUBSCRIBE
  3. PSUBSCRIBE
  4. PUNSUBSCRIBE
  5. PUBSUB CHANNELS
  6. PUBSUB NUMSUB
  7. PUBSUB NUMPAT

這7個命令的核心都是基於存儲在服務器狀態的pubsub_channels字典和pubsub_patterns鏈表實現的。

7. 參考

黃健宏 《Redis設計與實現》


注:若是以爲本篇博客有任何錯誤或者更好的建議,歡迎留言,我會及時跟進並更正博客內容!

文章持續更新,歡迎關注微信公衆號「申城異鄉人」第一時間閱讀!

相關文章
相關標籤/搜索