Redis的發(fā)布與訂閱

Redis的發(fā)布與訂閱

Redis的發(fā)布與訂閱功能由PUBLISH、SUBSCRIBE肾请、PSUBSCRIBE等命令組成。

1 頻道的訂閱與退訂

1.1訂閱頻道

命令:subscribe channel [channel..]
如subscribe “news.it”表示訂閱了"news.it"頻道

通過執(zhí)行SUBSCRIBE命令挽鞠,客戶端可以訂閱一個或多個頻道闹究,從而成為這些頻道的訂閱者(subscriber):每當有其他客戶端向被訂閱的頻道發(fā)送消息時(message)時霜瘪,頻道的所有訂閱者都會收到這條消息珠插。

當一個客戶端執(zhí)行SUBSCRIBE命令訂閱某個或某些頻道時,這個客戶端與被訂閱頻道之間就建立起了一種訂閱關系颖对。

Redis將所有頻道的訂閱關系都保存在服務器狀態(tài)的pubsub_channels字典(可以理解為redisServer中的一個map屬性)里面捻撑,這個字典的鍵是某個被訂閱的頻道,而值是一個鏈表缤底,鏈表的里面記錄了所有訂閱這個頻道的客戶端顾患。

struct redisServer{
    // ...
   // 保存所有頻道的訂閱關系
  dict *pubsub_channels;
  // ...
}

例如,客戶端1个唧、2江解、3訂閱了"news.it"頻道,客戶端4訂閱了"news.sport"頻道徙歼,客戶端5犁河、6訂閱了“news.bussiness”頻道,那么在pubsub_channels字典中的結構就如下圖所示魄梯。


一個pubsub_channels字典實例

每當客戶端執(zhí)行SUBSCRIBE命令訂閱某個或某些頻道時桨螺,服務器都會根據(jù)客戶端與被訂閱的頻道在pubsub_channels字典中進行關聯(lián)。

  • 如果頻道已經(jīng)有其他訂閱者酿秸,那么他在pubsub_channels字典中必然有相應的訂閱者鏈表灭翔,程序要做的就是將客戶端添加到訂閱者鏈表的末尾。
  • 如果頻道還沒有任何訂閱者辣苏,那么程序首先要在pubsub_channels字典中為頻道創(chuàng)建一個鍵肝箱,并將這個鍵的值設置為空鏈表,然后再將客戶端添加到鏈表稀蟋,成為鏈表的第一個元素狭园。
    如果客戶端7訂閱了news.sport和news.movie頻道,則pubsub_channels字典結構變成下圖所示糊治。


    執(zhí)行subscribe之后的pubsub_channels字典

1.2退訂頻道

UNSUBSCRIBE命令的行為和SUBSCRIBE命令的行為正好相反唱矛,當一個客戶端退訂某個或某些頻道的時候,服務器將從pubsub_channels中解除客戶端與被退訂頻道之間的關聯(lián):

  • 程序會根據(jù)被退訂頻道的名字,在pubsub_channels字典中找到頻道對應的訂閱鏈表绎谦,然后從訂閱鏈表中刪除退訂客戶端的信息管闷。
  • 如果刪除退訂客戶端后,頻道的訂閱鏈表變?yōu)榭真湵砬猿Γ敲凑f明這個頻道已經(jīng)沒有任何訂閱者了包个,程序?qū)膒ubsub_channels字典中刪除頻道對應的鍵。

2 模式的訂閱與退訂

2.1訂閱模式

前面說到冤留,服務器將所有頻道的訂閱關系都保存在服務器狀態(tài)的pubsub_channels屬性里面碧囊,與此類似,服務器也會將所有模式的訂閱關系保存在服務器狀態(tài)的pubsub_patterns屬性里纤怒。

struct redisServer{
  // ...
  // 保存所有的訂閱模式
  list *pubsub_patterns;
  // ...
}

pubsub_patterns屬性是一個鏈表糯而,鏈表中的每個節(jié)點都包含著一個pubsub_pattern結構,這個結構的pattern屬性記錄了被訂閱的模式泊窘,而client屬性記錄了訂閱模式的客戶端:

typedef struct pubsubPattern{

  // 訂閱模式的客戶端
  redisClient *client;

  // 被訂閱的模式
  robj *pattern;
}pubsubPattern

例如熄驼,客戶端8、9烘豹、10分別訂閱了"music.* "瓜贾、"book.* " 、"news.* "模式携悯,那么在pubsub_patterns鏈表結構就如下圖所示

pubsub_patterns鏈表

每當客戶端執(zhí)行PSUBSCIRBE命令訂閱某個或某些模式的時候祭芦,服務器會對每個訂閱模式執(zhí)行以下兩個操作:

  • 新建一個pubsubPattern結構,將結構的pattern屬性設置為訂閱的模式憔鬼,client屬性設置為被訂閱模式的客戶端实束。
  • 將pubsubPattern結構添加到pubsub_patterns鏈表的表尾部。

2.2 退訂模式

退訂模式和退訂頻道的原理類似逊彭,都是對鏈表節(jié)點刪除操作咸灿,這里不再累述。

3 發(fā)送消息

當一個Redis客戶端執(zhí)行PUBLISH <channel> <message>命令將消息發(fā)送給頻道<channel>的時候侮叮,服務器執(zhí)行以下兩個動作:

(1) 將消息message發(fā)送給channel頻道的所有訂閱者避矢。
(2) 如果有一個或多個模式pattern與頻道channel相匹配,那么消息message也會發(fā)送給pattern模式的訂閱者囊榜。

例如审胸,client-1訂閱了“news.it”頻道,client-2訂閱了模式"news.* "卸勺,那么當有客戶端執(zhí)行publish "news.it" “hello”砂沛,那么client-1和client-2都會收到消息。

3.1 將消息發(fā)送給頻道訂閱者

因為服務器狀態(tài)中的pubsub_channels字典記錄了所有頻道的訂閱關系曙求,所以為了將消息發(fā)送給channel頻道的所有訂閱者碍庵, PUBLISH命令要做的就是在pubsub_ channels字典里找到頻道channel的訂閱者名單(一個鏈表),然后將消息發(fā)送給名單上的所有客戶端静浴。
例如堰氓,某個客戶端執(zhí)行命令

publish "news.it" "hello"

那么PUBLISH命令會在pubsub_channels字典中查找鍵"news.it"對應的鏈表值,并通過遍歷鏈表將消息"hello"發(fā)送給client-1苹享、client-2双絮、client-3。

一個pubsub_channels字典實例

3.2將消息發(fā)送給模式訂閱者

因為服務器狀態(tài)中的pubsub_patterns鏈表記錄了所有模式的訂閱關系得问,所以為了將消息發(fā)送給所有與channel頻道相匹配的模式的訂閱者囤攀,PUBLISH命令要做的就是遍歷整個pubsub_patterns鏈表, 查找那些與channel頻道相匹配的模式宫纬, 并將消息發(fā) 送給訂閱了這些模式的客戶端焚挠。
例如,某個客戶端執(zhí)行命令

publish "news.it" "hello"

那么PUBLISH命令會首先將消息"hello"發(fā)送給"news.it"頻道的所有訂閱者哪怔,然后開始在pubsub_patterns鏈表中查找是否有被訂閱的模式與"news.it"頻道相匹配, 結果發(fā)現(xiàn)"news.it"頻道和客戶端client-10訂閱的"news.* "頻道匹配向抢, 于是命令將消息"hello"發(fā)送給客戶端client-10认境。

pubsub_patterns鏈表

4 查看訂閱信息

PUBSUB命令是Redis 2.8新增的命令,客戶端可以通過這個命令查看頻道或者模式的相關信息挟鸠。

4.1PUBSUB CHANNELS

PUBSUB CHANNELS [pattern]子命令用于返回服務器當前被訂閱的頻道叉信,其中pattern參數(shù)是可選的:

  • 如果不給定,則返回服務器當前被訂閱的所有頻道艘希。
  • 如果給定硼身,那么命令返回服務器當前被訂閱的頻道中那些與pattern模式相匹配的頻道。

這個子命令通過遍歷服務器pubsub_channels字典的所有鍵(每個鍵都是一個被訂閱的頻道)覆享,然后記錄并返回所有符合條件的頻道來實現(xiàn)佳遂。
對于下圖,如果執(zhí)行pubsub channels撒顿,將返回:

(1) "news.it"
(2) "news.sport"
(3) "news.bussiness"

如果執(zhí)行pubsub channels “news.[is]* ”,命令將返回:

(1) "news.it"
(2) "news.sport"

一個pubsub_channels字典實例

4.2 PUBSUB NUMSUB

PUBSUB NUMSUB [channel-1 channel-2 ...]子命令接受任意多個頻道作為輸入?yún)?shù)丑罪,并返回這些頻道的訂閱者數(shù)量。
這個子命令通過在pubsub_channels字典中找到頻道對應的訂閱者鏈表凤壁,然后返回訂閱者鏈表的長度來實現(xiàn)的(訂閱者鏈表的長度就是頻道訂閱者的數(shù)量)吩屹。
例如,對上圖的pubsub_channels字典實例結構執(zhí)行:pubsub numsub "news.it" "news sport" "news bussiness",將返回:

1) "news.it"
2) "3"
3) "news.sport"
4) "1" 
5) "news.sport"
6) "2"

4.3 PUBSUB NUMPAT

PUBSUB NUMPAT子命令用于返回服務器當前訂閱模式的數(shù)量拧抖。
這個子命令 通過返回pubsub_patterns鏈表的長度來實現(xiàn)的煤搜,因為這個鏈表的長度就是服務器訂閱模式的數(shù)量。
對于下圖唧席,如果執(zhí)行pubsub numpat擦盾,將返回

(integer) 3

pubsub_patterns鏈表

5 小結

(1) 服務器狀態(tài)在pubsub_channels字典保存了所有頻道的訂閱關系嘲驾,在pubsub_patterns鏈表中保存了所有模式的訂閱關系。
(2) 客戶端向一個頻道發(fā)送一條消息時厌衙,不僅所有訂閱了該頻道的客戶端會接收到這條消息距淫,與該頻道相匹配的訂閱模式的客戶端也會收到這條消息。
(3) PUBSUB命令的三個子命令都是通過讀取pubsub_patterns鏈表或pubsub_channels字典中的信息來實現(xiàn)的婶希。

本文完

注:本文參考《Redis設計與實現(xiàn)》榕暇,如發(fā)現(xiàn)錯誤,請指正喻杈!

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末彤枢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子筒饰,更是在濱河造成了極大的恐慌缴啡,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓷们,死亡現(xiàn)場離奇詭異业栅,居然都是意外死亡,警方通過查閱死者的電腦和手機谬晕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門碘裕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人攒钳,你說我怎么就攤上這事帮孔。” “怎么了不撑?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵文兢,是天一觀的道長。 經(jīng)常有香客問我焕檬,道長姆坚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任实愚,我火速辦了婚禮旷偿,結果婚禮上,老公的妹妹穿的比我還像新娘爆侣。我一直安慰自己萍程,他們只是感情好,可當我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布兔仰。 她就那樣靜靜地躺著茫负,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乎赴。 梳的紋絲不亂的頭發(fā)上忍法,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天潮尝,我揣著相機與錄音,去河邊找鬼饿序。 笑死勉失,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的原探。 我是一名探鬼主播乱凿,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼咽弦!你這毒婦竟也來了徒蟆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤型型,失蹤者是張志新(化名)和其女友劉穎段审,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闹蒜,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡寺枉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绷落。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姥闪。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嘱函,靈堂內(nèi)的尸體忽然破棺而出甘畅,到底是詐尸還是另有隱情埂蕊,我是刑警寧澤往弓,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站蓄氧,受9級特大地震影響函似,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喉童,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一撇寞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧堂氯,春花似錦蔑担、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晶框,卻和暖如春排抬,著一層夾襖步出監(jiān)牢的瞬間懂从,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工蹲蒲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留番甩,地道東北人。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓届搁,卻偏偏與公主長得像缘薛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子咖祭,可洞房花燭夜當晚...
    茶點故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容