Redis學習筆記(二十) 釋出訂閱(下)

溫暖如太陽發表於2020-06-12

當一個客戶端執行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設計與實現》,僅在此做學習與大家分享。

 


 

 

相關文章