一、什么是pub/sub?
publish/subscribe ,即發布訂閱功能。基於實踐系統中,是常用的通信模型,采用事件做為基本的通信機制,提供大規模系統要求的松散耦合的交互方式。訂閱者,以事件定義的方式表達出它有興趣接受的一個時間或一類事件。發布者,發布事件並通知相關訂閱者。
同時,pub/sub也是一個消息通信模式,主要目的是解除消息發布者和訂閱者之間的耦合,Redis作為pub/sub的一個server,在發布者和訂閱者之間起到了消息路由的作用。
二、Redis實現原理簡單總結
pub/sub功能提供兩種信息機制,分別是“訂閱/發布到頻道”和“訂閱/發布到模式”。
1、頻道的訂閱與信息發送
語法介紹: 【訂閱頻道】subscribe channel1 channel2 ··· 【頻道發布信息】publish channel1 message 【退訂頻道】unsubscribe channel1 ···
訂閱頻道的存儲:在redis服務中都維持着一個表示服務器狀態的 redis.h/redisServer結構,結構中pubsub_channels屬性是一個字典,用於保存訂閱信息。
保存結構:該字典是一個鍵值對,鍵為正在被訂閱的頻道,值則是一個鏈表,鏈表中保存所有訂閱這個頻道的客戶端。
struct redisServer {
//...
dict *pubsub_channels;
//...
}
當再次發生訂閱操作,先遍歷pubsub_channels的鍵,如果有就在對應值的鏈表結尾添加客戶端信息。
因此程序可以通過pubsub_channels來確定某個頻道是否正被訂閱,也可以通過頻道拿到所有訂閱該頻道的客戶端信息。
頻道發布信息:在某頻道發布信息,遍歷pubsub_channels找到訂閱該頻道的所有客戶端,發送信息。
2、模式的訂閱與信息發送
語法介紹:【訂閱模式】psubscribe channel* ··· 【punsubscribe channel* ···】
訂閱模式的存儲: redisServer.pubsub_patterns屬性是一個鏈表,鏈表中每個節點都包含一個redis.h/pubsubPattern結構。
pubsubPattern中client保存訂閱模式的客戶端,pattern則保存被訂閱的模式。
struct redisServer { typedef struct pubsubPattern {
//... redisClient *client;
list *pubsub_patterns; robj *pattern;
//... } pubsubPattern;
};
發布信息:除了遍歷頻道外,還需匹配模式,然后發送信息。
三、項目中應用
參照項目:com.liuxs.runToExpert.redis.pubSub.plus
注意點:
1、發布和訂閱主要依賴於 redis.clients.jedis.JedisPubSub 監聽器,所有操作都會在其實現類中對應方法做監聽處理。
2、如果用同一個jedis對象(即使沒有做單例,從jedisPool中拿的)來發布、訂閱,都會拋出一個異常。
異常信息:JedisDataException: ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in...
3、取消訂閱功能,只有在監聽過程中調用器父類的unsubsribe(channel)實現,如果直接調用拋出會找不到Client異常。