小試身手—— Redis之發(fā)布/訂閱機制

相關(guān)命令:

PUBLISH? ? ? ? ? ? 發(fā)布

SUBSCRIBE? ? ? ? ? 訂閱

PSUBSCRIBE? ? ? ? ? 一種訂閱符合給定模式的所有頻道的方法

UNSUBSCRIBE? ? ? ? 退訂

PUNSUBSCRIBE? ? ? ? 退訂一個訂閱的模式

這些命令被廣泛用于構(gòu)建即時通信應(yīng)用,比如網(wǎng)絡(luò)聊天室(chatroom)和實時廣播燎窘、實時提醒等弧岳。

Redis相關(guān)源碼文件:pubsub.c

使用

PUBLISH 命令用于向給定的頻道發(fā)送信息轻局,返回值為接收到信息的訂閱者數(shù)量

redis> PUBLISH treehole "top secret here ..."

(integer) 0

redis> PUBLISH chatroom "hi?"

(integer) 1

SUBSCRIBE 命令訂閱給定的一個或多個頻道:

? redis> SUBSCRIBE chatroom

  Reading messages... (press Ctrl-C to quit)

  1) "subscribe" # 訂閱反饋

  2) "chatroom" # 訂閱的頻道

  3) (integer) 1 # 目前客戶端已訂閱頻道/模式的數(shù)量

  1) "message" # 信息

  2) "chatroom" # 發(fā)送信息的頻道

  3) "hi?" # 信息內(nèi)容

SUBSCRIBE 的返回值當中诲祸, 1) ""subscribe""是訂閱的反饋信息歉铝,1)"message "的則是訂閱的頻道所發(fā)送的信息。

SUBSCRIBE 還可以訂閱多個頻道谍婉,這樣一來它接收到的信息就可能來自多個頻道:

redis> SUBSCRIBE chatroom talk-to-jack

  Reading messages... (press Ctrl-C to quit)

  1) "subscribe" # 訂閱 chatroom 的反饋

  2) "chatroom"

  3) (integer) 1

  1) "subscribe" # 訂閱 talk-to-jack 的反饋

  2) "talk-to-jack"

  3) (integer) 2

  1) "message" # 來自 chatroom 的消息

  2) "chatroom"

  3) "yahoo"

  1) "message" # 來自 talk-to-peter 的消息

  2) "talk-to-jack"

  3) "Goodmorning, peter."

PSUBSCRIBE 提供了一種訂閱符合給定模式的所有頻道的方法更啄,比如說稚疹,使用 it.* 為輸入,就可以訂閱所有以 it. 開頭的頻道祭务,比如 it.news 内狗、 it.blog 、 it.tweets 义锥,諸如此類:

redis> PSUBSCRIBE it.*

  Reading messages... (press Ctrl-C to quit)

  1) "psubscribe"

  2) "it.*"

  3) (integer) 1

  1) "pmessage"

  2) "it.*" # 匹配的模式

  3) "it.news" # 消息的來源頻道

  4) "Redis 2.6rc5 release" # 消息內(nèi)容

  1) "pmessage"

  2) "it.*"

  3) "it.blog"

  4) "Why NoSQL matters"

  1) "pmessage"

  2) "it.*"

  3) "it.tweet"

  4) "@redis: when will the 2.6 stable release?"

當然柳沙, PSUBSCRIBE 也可以接受多個參數(shù),從而匹配多種模式拌倍。

UNSUBSCRIBE 和 PUNSUBSCRIBE 負責退訂給定的頻道或模式赂鲤。


內(nèi)部實現(xiàn)

流程

當一個客戶端通過 PUBLISH 命令向訂閱者發(fā)送信息的時候,我們稱這個客戶端為發(fā)布者(publisher)柱恤。

而當一個客戶端使用 SUBSCRIBE 或者 PSUBSCRIBE 命令接收信息的時候数初,我們稱這個客戶端為訂閱者(subscriber)。

為了解耦發(fā)布者(publisher)和訂閱者(subscriber)之間的關(guān)系梗顺,Redis 使用了 channel (頻道)作為兩者的中介 —— 發(fā)布者將信息直接發(fā)布給 channel 泡孩,而 channel 負責將信息發(fā)送給適當?shù)挠嗛喺撸l(fā)布者和訂閱者之間沒有相互關(guān)系寺谤,也不知道對方的存在

具體實現(xiàn)

SUBSCRIBE 命令的實現(xiàn)

Redis 將所有接受和發(fā)送信息的任務(wù)交給 channel 來進行珍德,而所有 channel 的信息就儲存在 redisServer 這個結(jié)構(gòu)中:

struct redisServer {

  // ......

  dict *pubsub_channels;? ? // Map channels to list of subscribed clients

  // ......

  };

pubsub_channels 是一個字典,字典的鍵就是一個個 channel 矗漾,而字典的值則是一個鏈表,鏈表中保存了所有訂閱這個 channel 的客戶端薄料。(haspmap之類)

實現(xiàn) SUBSCRIBE 命令的關(guān)鍵敞贡,就是將客戶端添加到給定 channel 的訂閱鏈表中。

函數(shù) pubsubSubscribeChannel 是 SUBSCRIBE 命令的底層實現(xiàn)摄职,它完成了將客戶端添加到訂閱鏈表中的工作:

? ? // 訂閱指定頻道

  // 訂閱成功返回 1 誊役,如果已經(jīng)訂閱過获列,返回 0

  int pubsubSubscribeChannel(redisClient *c, robj *channel) {

  struct dictEntry *de;

  list *clients = NULL;

  int retval = 0;

  /* Add the channel to the client -> channels hash table */

  // dictAdd 在添加新元素成功時返回 DICT_OK

  // 因此這個判斷句表示,如果新訂閱 channel 成功蛔垢,那么 击孩。。鹏漆。

  if (dictAdd(c->pubsub_channels,channel,NULL) == DICT_OK) {

  retval = 1;

  incrRefCount(channel);

  /* Add the client to the channel -> list of clients hash table */

  // 將 client 添加到訂閱給定 channel 的鏈表中

  // 這個鏈表是一個哈希表的值巩梢,哈希表的鍵是給定 channel

  // 這個哈希表保存在 server.pubsub_channels 里

  de = dictFind(server.pubsub_channels,channel);

  if (de == NULL) {

  // 如果 de 等于 NULL

  // 表示這個客戶端是首個訂閱這個 channel 的客戶端

  // 那么創(chuàng)建一個新的列表, 并將它加入到哈希表中

  clients = listCreate();

  dictAdd(server.pubsub_channels,channel,clients);

  incrRefCount(channel);

  } else {

  // 如果 de 不為空艺玲,就取出這個 clients 鏈表

  clients = dictGetVal(de);

  }

  // 將客戶端加入到鏈表中

  listAddNodeTail(clients,c);

  }

  /* Notify the client */

  addReply(c,shared.mbulkhdr[3]);

  addReply(c,shared.subscribebulk);

  // 返回訂閱的頻道

  addReplyBulk(c,channel);

  // 返回客戶端當前已訂閱的頻道和模式數(shù)量的總和

  addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns));

  return retval;

  }

PSUBSCRIBE 命令的實現(xiàn)

和 redisServer.pubsub_channels 屬性類似括蝠, redisServer.pubsub_patterns 屬性用于保存所有被訂閱的模式,和 pubsub_channels 不同的是饭聚, pubsub_patterns 是一個鏈表(而不是字典):

struct redisServer {

  // ......

  list *pubsub_patterns; // A list of pubsub_patterns

  // ......

  };

“我自己是一名Java架構(gòu)師忌警,辭職目前在做講師,整理了一份學(xué)習Java干貨秒梳,無論是剛需的高級面試專題還是常用的數(shù)據(jù)算法都有整理法绵,送給每一位Java小伙伴。在日新月異的程序世界里酪碘,我們每一個人都是學(xué)生朋譬。"

加群:712477306 (招募中)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市婆跑,隨后出現(xiàn)的幾起案子此熬,更是在濱河造成了極大的恐慌,老刑警劉巖滑进,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件犀忱,死亡現(xiàn)場離奇詭異,居然都是意外死亡扶关,警方通過查閱死者的電腦和手機阴汇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來节槐,“玉大人搀庶,你說我怎么就攤上這事⊥欤” “怎么了哥倔?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長揍庄。 經(jīng)常有香客問我咆蒿,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任沃测,我火速辦了婚禮缭黔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蒂破。我一直安慰自己馏谨,他們只是感情好,可當我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布附迷。 她就那樣靜靜地躺著惧互,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挟秤。 梳的紋絲不亂的頭發(fā)上壹哺,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天,我揣著相機與錄音艘刚,去河邊找鬼管宵。 笑死,一個胖子當著我的面吹牛攀甚,可吹牛的內(nèi)容都是我干的箩朴。 我是一名探鬼主播,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼秋度,長吁一口氣:“原來是場噩夢啊……” “哼炸庞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荚斯,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤埠居,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后事期,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滥壕,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年兽泣,在試婚紗的時候發(fā)現(xiàn)自己被綠了绎橘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡唠倦,死狀恐怖称鳞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情稠鼻,我是刑警寧澤冈止,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布,位于F島的核電站候齿,受9級特大地震影響熙暴,放射性物質(zhì)發(fā)生泄漏苫亦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一怨咪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧润匙,春花似錦诗眨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至厂财,卻和暖如春芋簿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背璃饱。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工与斤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荚恶。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓撩穿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谒撼。 傳聞我的和親對象是個殘疾皇子食寡,可洞房花燭夜當晚...
    茶點故事閱讀 43,576評論 2 349

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

  • redis-訂閱與發(fā)布 Redis 通過 PUBLISH 、 SUBSCRIBE 等命令實現(xiàn)了訂閱與發(fā)布模式廓潜, 這...
    全能程序猿閱讀 5,840評論 0 4
  • 本文主要說明Redis中發(fā)布與訂閱功能的設(shè)計與實現(xiàn)抵皱。 I、上帝視角看發(fā)布于訂閱 Redis主要通過PUBLISH辩蛋,...
    wenmingxing閱讀 617評論 0 1
  • Redis的發(fā)布與訂閱功能由PUBLISH呻畸、SUBSCRIBE、PSUBSCRIBE等命令組成堪澎。通過SUBSCRI...
    涵仔睡覺閱讀 554評論 0 0
  • 今天看了秋葉大叔的書《和秋葉一起學(xué)PPT》擂错,做了些筆記,現(xiàn)在整理一下分享給大家樱蛤。 好的PPT體現(xiàn)了設(shè)計者的邏輯和美...
    Clover0124閱讀 889評論 4 14
  • 《刺客聶隱娘》確實是一部不太容易看懂的電影钮呀,或者說,是一部不太那么大眾的電影昨凡。 不太容易看懂爽醋,我以為有以下幾個方面...
    菜園子閱讀 2,364評論 9 31