《Redis設計與實現》讀書筆記(三十二) ——Redis集釋出訂閱設計與實現
《Redis設計與實現》讀書筆記(三十二) ——Redis集釋出訂閱設計與實現
(原創內容,轉載請註明來源,謝謝)
一、概述
redis的釋出訂閱由publish、subscribe、psubscribe等命令組成。客戶端通過subscribe訂閱頻道,釋出端通過publish進行釋出。
例如,a、b、c三個客戶端都執行了命令subscribe“new.it”,則表示這三個客戶端都監聽該頻道的資訊。此時,如果某個客戶端執行publish “new.it” “hello”,則a、b、c三個客戶端都會收到該訊息。
每個客戶端都可以訂閱多個頻道,每個頻道也可以給多個客戶端訂閱,屬於多對多關係。
如上圖所示,當訊息發到news.it頻道,則a、c、d三個客戶端都會收到訊息。
二、頻道訂閱與退訂
1、訂閱
當客戶端執行subscribe命令,客戶端和頻道之間就形成訂閱的關係,redis將所有頻道的訂閱關係放在redisServer結構體的pubsub_channels字典中,這個字典的鍵是被訂閱的頻道,值是連結串列,連結串列裡面記錄了所有訂閱這個頻道的客戶端。
每當有客戶端訂閱頻道,伺服器都會將字典中的頻道與客戶端關聯。如果頻道已經有其他訂閱者,則該客戶端加到連結串列的末尾;如果頻道還沒有訂閱者,則不存在於pubsub_channels字典,則會新建立一個鍵值對。
2、退訂
unsubscribe命令是退訂的命令,客戶端執行此命令退訂某個頻道,則伺服器會將鍵對應的連結串列的節點刪除。另外,如果刪除連結串列的節點後,該頻道的鍵對應的連結串列是空,表示此時沒有客戶端定義該頻道,則該鍵也會被刪除。
三、模式的訂閱與退訂
1、訂閱模式
模式的訂閱與退訂儲存在redisServer結構體的列表pubsub_patterns中,該list是一個連結串列,每個節點包含一個pubsub_pattern結構,如下:
typedef struct pubsubPattern{
redisClient *client;
robj *pattern;
}pubsubPattern;
這個結構的pattern記錄了訂閱的模式,而client記錄了定閱該模式的客戶端。
當客戶端執行psubscribe命令,即訂閱某個模式,redis伺服器會新建一個pubsubPattern節點,並且將client資訊進行記錄。
2、退訂模式
punsubscribe命令是退訂模式的命令。當退訂模式,伺服器會將客戶端的資訊從模式對應的pubsubPattern結構體刪除。
四、傳送訊息
redis任一客戶端執行publish <channel><message>,表示其傳送訊息,其會將訊息傳送給頻道訂閱者與模式訂閱者。
1、傳送給頻道訂閱者
由於pubsub_channels字典記錄所有頻道的訂閱關係,則redis伺服器會從頻道的字典中,找到channel訂閱者的名單,即一個連結串列,並將訊息傳送給其中的所有的訂閱者。
2、傳送給模式訂閱者
由於pubsub_patterns是一個連結串列形式,記錄所有的模式訂閱者的資訊,因此redis會遍歷該連結串列,找到所有與當前channel匹配的模式,並將訊息傳送給這些模式的客戶端。
五、檢視訂閱資訊
pubsub命令可以用於檢視頻道的訂閱情況,其共有三個子命令。
1、pubsubchannels
pubsub channels [pattern]命令用於返回伺服器當前被訂閱的頻道,pattern引數可選,不給定引數,返回當前所有頻道;給定引數,返回當前頻道中與pattern模式匹配的頻道。
該命令是通過遍歷pubsub_channels字典,檢視所有匹配的頻道。
2、pubsubnumsub
pubsub numsub [channel-1 channel-2 …]子命令接收多個頻道作為引數,返回這些頻道訂閱者的數量。
該命令是通過遍歷pattern_channels字典,找到需要查閱的頻道,並且返回頻道對應的連結串列的長度。如果頻道沒有被訂閱,則返回0。
3、pubsubnumpat
pubsub numpat返回伺服器當前被訂閱的模式的數量。
該命令是通過返回pubsub_patterns連結串列的長度來實現的。
六、總結
1、訂閱分為頻道訂閱和模式訂閱。伺服器在redisServer結構體的字典pubsub_channels中,以鍵作為頻道名稱,值是所有訂閱該頻道的連結串列;在連結串列pubsub_patterns中,記錄所有被訂閱的模式以及對應的客戶端資訊。
2、頻道訂閱與退訂命令分別是subscribe、unsubscribe,模式訂閱與退訂命令分別是psubscribe、punsubscribe,釋出命令是publish。
3、publish命令通過訪問pubsub_channel來找到頻道訂閱者,通過pubsub_patterns找到模式訂閱者,並且傳送訊息。
——written by linhxx 2017.09.26