Redis的發佈與訂閱,有點類似於消息隊列,發送者往頻道發送消息,頻道的訂閱者接收消息。 1. 發佈與訂閱示例 首先,在本機開啟第1個Redis客戶端,執行如下命令訂閱blog.redis頻道: SUBSCRIBE "blog.redis" 然後,在本機開啟第2個Redis客戶端,執行相同的命令訂閱 ...
Redis的發佈與訂閱,有點類似於消息隊列,發送者往頻道發送消息,頻道的訂閱者接收消息。
1. 發佈與訂閱示例
首先,在本機開啟第1個Redis客戶端,執行如下命令訂閱blog.redis
頻道:
SUBSCRIBE "blog.redis"
然後,在本機開啟第2個Redis客戶端,執行相同的命令訂閱blog.redis
頻道:
然後,開啟第3個Redis客戶端,執行如下命令往blog.redis
頻道發送消息:
PUBLISH blog.redis "redis-in-action-01"
查看客戶端1和客戶端2,分別看到如下信息:
3個客戶端與頻道的關係如下圖所示:
可以通過INFO clients
命令查看連接的客戶端數:
2. 訂閱/退訂頻道
2.1 訂閱頻道
Redis的SUBSCRIBE
命令用來訂閱頻道,使用方式如下所示:
SUBSCRIBE "blog.redis"
如果是訂閱多個頻道,可以使用如下所示命令:
SUBSCRIBE "blog.redis" "blog.rocketmq"
Redis將所有頻道的訂閱關係保存在伺服器狀態的pubsub_channels
字典里,字典的鍵是某個被訂閱的頻道,鍵對應的值是1個鏈表,鏈表裡記錄了所有訂閱這個頻道的客戶端。
以上圖為例,說明客戶端1、客戶端2正在訂閱頻道"blog.redis",客戶端3、客戶端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個動作:
- 將消息"redis-in-action-01"發送給頻道“blog.redis”的所有訂閱者
- 將消息"redis-in-action-01"發送給與頻道“blog.redis”相匹配模式的訂閱者
也就是說,消息"redis-in-action-01"不僅會發送給頻道“blog.redis”的訂閱者客戶端1、客戶端2,也會發送給與頻道“blog.redis”相匹配的模式“blog.r*”的訂閱者客戶端5。
5. 查看訂閱信息
可以使用Redis的PUBSUB
命令來查看頻道或者模式的相關信息。
5.1 查看被訂閱的頻道
如果想要查看被訂閱的頻道信息,可以使用命令PUBSUB CHANNELS [pattern]
,其中pattern參數是可選的:
- 如果不指定pattern參數,返回伺服器當前被訂閱的所有頻道
- 如果指定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個命令:
- SUBSCRIBE
- UNSUBSCRIBE
- PSUBSCRIBE
- PUNSUBSCRIBE
- PUBSUB CHANNELS
- PUBSUB NUMSUB
- PUBSUB NUMPAT
這7個命令的核心都是基於存儲在伺服器狀態的pubsub_channels
字典和pubsub_patterns
鏈表實現的。
7. 參考
黃健巨集 《Redis設計與實現》