當一個客戶端執行SUBSCRIBE命令訂閱某個或某些頻道時,這個客戶端與被訂閱頻道之間就建立起了一種訂閱關係。 Redis將所有頻道的訂閱關係保存在伺服器狀態的pubsub_channels字典裡面,這個字典的鍵是某個被訂閱的頻道,而鍵的值是一個鏈表,鏈表裡面記錄了所有訂閱這個頻道的客戶端: str ...
當一個客戶端執行SUBSCRIBE命令訂閱某個或某些頻道時,這個客戶端與被訂閱頻道之間就建立起了一種訂閱關係。
Redis將所有頻道的訂閱關係保存在伺服器狀態的pubsub_channels字典裡面,這個字典的鍵是某個被訂閱的頻道,而鍵的值是一個鏈表,鏈表裡面記錄了所有訂閱這個頻道的客戶端:
struct redisServer{ //保存所有頻道的訂閱關係 dict *pubsub_channels; }
如果頻道已經有其他的訂閱者,那麼他在pubsub_channels字典中必然有相應的訂閱者鏈表,程式唯一要做的就是將客戶端添加到訂閱者鏈表的末尾,反之程式首先要在pubsub_channels字典中為頻道創建一個鍵,並將這個鍵的值設置為空鏈表,然後將客戶端添加到鏈表,成為鏈表的第一個元素。
UNSUBSCRIBE命令的行為與SUBSCRIBE命令相反,當一個客戶端推定某個或某些頻道的時候,伺服器將從pubsub_channels中接觸客戶端與被訂閱頻道之間的關聯:程式會根據被推定頻道的名字,在publish_channels字典中找到頻道對應的訂閱鏈表,而後從訂閱者鏈表中刪除退訂客戶端的信息;如果刪除推定客戶端之後,頻道的訂閱者鏈表變成空鏈表,那麼說明頻道已經沒有了訂閱者了,程式將從pubsub_channels字典中刪除頻道對應的鍵。
伺服器將所有頻道的訂閱關係都保存在伺服器狀態的pubsub_channels屬性裡面,與之相似,伺服器也將所有模式的訂閱關係都保存在伺服器狀態的pubsub_patterns屬性裡面:
struct redisServer { //保存所有訂閱關係 list *pubsub_patterns; };
pubsub_patterns屬性是一個鏈表,鏈表中的每個節點都包含著一個pubsubpattern結構,這個結構的pattern屬性記錄了被訂閱的模式,而client屬性則記錄了訂閱模式的客戶端:
typedef struct pubsubPattern{ //訂閱模式的客戶端 redisClient *client; //被訂閱的模式 robj *pattern; } pubsubPattern;
訂閱模式
每當客戶端執行PSUBSCRIBE命令訂閱某個或某些模式的時候,伺服器會對某個被訂閱的模式執行:新建一個pubsubPattern結構,將結構的pattern屬性設置為被訂閱的模式,client屬性設置為訂閱模式的客戶端;將pubsubPattern結構添加到pubsub_patterns鏈表的表尾。
發送消息
當一個Redis客戶端執行PUBLISH < channel > < message > 命令將消息message發送給頻道channel的時候,伺服器需要執行以下兩個動作:將消息message發送給channel頻道的所有訂閱者;如果有一個或多個模式pattern與頻道channel相匹配,那麼將消息message發送給pattern模式的訂閱者。
因為伺服器狀態中pubsub_channels字典記錄了所有頻道的訂閱關係,所以為了將消息發送給channel頻道的所有訂閱者,PUBLISH命令要做的就是在subsub_channels字典里找到頻道channel的訂閱者名單(鏈表),然後將消息發送給名單上的所有客戶端。
將消息發送欸模式訂閱者,因為伺服器狀態中的pubsub_patterns鏈表記錄了所有模式的訂閱關係,所以為了將消息發送給所有與channel頻道相匹配的模式的訂閱者,PUBLISH命令要做的就是遍歷整個pubsub_patterns鏈表,查找那些與channel頻道相匹配的模式,並將消息發送給訂閱了謝謝模式的客戶端。
PUBSUB CHANNELS 【pattern】子命令用於返回伺服器當前被訂閱的頻道,如果【pattern】參數不給定,那麼命令返回伺服器當前被訂閱的所有頻道。
PUBSUB NUMSUB 子命令接收任意多個頻道作為輸入參數,並返回這些頻道的訂閱者數量。
PUBSUB NUMPAT子命令用於返回伺服器當前訂閱模式的數量
每天學一點,總會有收穫。
說明:尊重作者知識產權,文中內容參考《Redis設計與實現》,僅在此做學習與大家分享。