新聞中心
Redis發(fā)布/訂閱應(yīng)用
這一篇我們來看看Redis好玩的發(fā)布訂閱模式,其實在很多的MQ產(chǎn)品中都存在這樣的一個模式,我們常聽到的一個例子就是郵件訂閱的場景,什么意思呢,也就是說100個人訂閱了你的博客,如果博主發(fā)表了文章,那么100個人就會同時收到通知郵件,除了這個場景還能找到其他場景么,當(dāng)然有啦,你想想,如果你要在內(nèi)存里面做一個讀寫分離的程序,為了維持?jǐn)?shù)據(jù)的完整性,你是不是需要保證在寫入的時候,也要分發(fā)到各個讀內(nèi)存的程序中呢?所以說場景還是很多的,在于你的挖掘~~~

發(fā)布訂閱(pub/sub)是一種消息通信模式,主要的目的是解耦消息發(fā)布者和消息訂閱者之間的耦合,這點和設(shè)計模式中的觀察者模式比較相似。pub /sub不僅僅解決發(fā)布者和訂閱者直接代碼級別耦合也解決兩者在物理部署上的耦合。redis作為一個pub/sub server,在訂閱者和發(fā)布者之間起到了消息路由的功能。訂閱者可以通過subscribe和psubscribe命令向redis server訂閱自己感興趣的消息類型,redis將消息類型稱為通道(channel)。當(dāng)發(fā)布者通過publish命令向redis server發(fā)送特定類型的消息時。訂閱該消息類型的全部client都會收到此消息。這里消息的傳遞是多對多的。一個client可以訂閱多個 channel,也可以向多個channel發(fā)送消息。
下面還是從基本命令入手:
PSUBSCRIBE pattern [pattern ...] #訂閱一個或多個符合給定模式的頻道;
PUBSUB subcommand [argument [argument ...]] #查看訂閱與發(fā)布系統(tǒng)狀態(tài);
PUBLISH channel message #將信息發(fā)送到指定的頻道;
PUNSUBSCRIBE [pattern [pattern ...]] #退訂所有給定模式的頻道;
SUBSCRIBE channel [channel ...] #訂閱給定的一個或多個頻道的信息;
UNSUBSCRIBE [channel [channel ...]] #指退訂給定的頻道;
從redis手冊上面可以看到,其實“發(fā)布、訂閱”模式才區(qū)區(qū)6個命令,下面聽我一一解說下
SUBSCRIBE
訂閱給定的一個或多個頻道的信息。
SUBSCRIBE channel [channel ...]
從上面的官方解釋上來看,它的玩法有一點像現(xiàn)實生活中我們聽收音機一個道理,要想聽收音機,我們要做什么?肯定就是調(diào)頻啦,只有在正確的頻道上面,我們才能聽得到好聽的節(jié)目,所以說subscribe首先要訂閱一個頻道(channel),下面我舉個例子,開兩個client,分別訂閱著msg這個頻道,比如下面這樣:
root@localhost:~ # redis-cli -p 6379
127.0.0.1:6379> SUBSCRIBE msg
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "msg"
3) (integer) 1
root@localhost:~ # redis-cli -p 6379
127.0.0.1:6379> SUBSCRIBE msg
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "msg"
3) (integer) 1
SUBSCRIBE還可以訂閱多個頻道,這樣一來它接收到的信息就可能來自多個頻道。
PUBLISH
到現(xiàn)在為止,這兩個subscibe都在監(jiān)視著msg這個頻道,接下來,如果msg頻道有消息傳出,必定會被subscribe接收到,我們還是先看看redis手冊上怎么用這個命令。
將信息message發(fā)送到指定的頻道channel。
PUBLISH channel message
如下演示:
看到么有,publish在msg這個頻道上面發(fā)送消息后,被subscribe監(jiān)視到了,然后就被分別打印輸出了,好了,到現(xiàn)在為止,最基本的發(fā)布訂閱模式就是這樣,是不是很簡單哈。其實呢??? 也就是這么簡單吶,但是呢,有時候我們還有這樣一個需求,就是我能不能模糊匹配key呢?舉了例子,就是要求訂閱china為前綴的所有頻道,如果這樣也可以做到的話,那確實是很牛逼啦。。。我要是回答的話,當(dāng)然啦,強大的Redis自然會做到這一點,它提供了的命令就是:PSUBSCRIBE。
PSUBSCRIBE
訂閱一個或多個符合給定模式的頻道,每個模式以作為匹配符,比如it匹配所有以it開頭的頻道(it.news、it.blog、it.tweets等等),news.*匹配所有以news.開頭的頻道(news.it、 news.global.today 等等),諸如此類。
PSUBSCRIBE pattern [pattern ...]
看到上面的解釋,你心里可能就在想,這不就是正則匹配么。。。而且前綴”P”就是Pattern的意思,對吧,接下來我就訂閱一下所有china為前綴的channel。
當(dāng)然,PSUBSCRIBE 也可以接受多個參數(shù),從而匹配多種模式??赐暌粋€小例子后應(yīng)該對pub/sub功能有了一個感性的認(rèn)識,需要注意的是當(dāng)一個連接通過subscribe或者psubscribe訂閱通道后就進入訂閱模式。在這種模式除了再訂閱額外的通道或者用unsubscribe或者punsubscribe命令退出訂閱模式,就不能再發(fā)送其他命令。另外使用 psubscribe命令訂閱多個通配符通道,如果一個消息匹配上了多個通道模式的話,會多次收到同一個消息。
Redis的pub/sub還是有點太單薄(實現(xiàn)才用150行代碼)。在安全,認(rèn)證,可靠性這方便都沒有太多支持。
Redis發(fā)布/訂閱機制
當(dāng)一個客戶端通過 PUBLISH 命令向訂閱者發(fā)送信息的時候,我們稱這個客戶端為發(fā)布者(publisher)。
而當(dāng)一個客戶端使用 SUBSCRIBE 或者 PSUBSCRIBE 命令接收信息的時候,我們稱這個客戶端為訂閱者(subscriber)。
為了解耦發(fā)布者(publisher)和訂閱者(subscriber)之間的關(guān)系,Redis 使用了 channel (頻道)作為兩者的中介 —— 發(fā)布者將信息直接發(fā)布給 channel ,而 channel 負(fù)責(zé)將信息發(fā)送給適當(dāng)?shù)挠嗛喺?,發(fā)布者和訂閱者之間沒有相互關(guān)系,也不知道對方的存在:
知道了發(fā)布和訂閱的機制之后,接下來就可以開始研究具體的實現(xiàn)了,我們從Redis的訂閱命令開始說起。
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的客戶端。
舉個例子,如果在一個 redisServer 實例中,有一個叫做 news 的頻道,這個頻道同時被client_123 和 client_456 兩個客戶端訂閱,那么這個 redisServer 結(jié)構(gòu)看起來應(yīng)該是這樣子:
可以看出,實現(xiàn)SUBSCRIBE命令的關(guān)鍵,就是將客戶端添加到給定channel的訂閱鏈表中。
PSUBSCRIBE命令的實現(xiàn)
除了直接訂閱給定channel外,還可以使用PSUBSCRIBE訂閱一個模式(pattern),訂閱一個模式等同于訂閱所有匹配這個模式的channel 。
和redisServer.pubsub_channels屬性類似,redisServer.pubsub_patterns屬性用于保存所有被訂閱的模式,和pubsub_channels不同的是, pubsub_patterns是一個鏈表(而不是字典):
struct redisServer {
// 省略 ...
list *pubsub_patterns; // A list of pubsub_patterns
// 省略 ...
};
pubsub_patterns 的每一個節(jié)點都是一個 pubsubPattern 結(jié)構(gòu)的實例,它保存了被訂閱的模式,以及訂閱這個模式的客戶客戶端:
typedef struct pubsubPattern {
redisClient *client;
robj *pattern;
} pubsubPattern;
舉個例子,假設(shè)在一個 redisServer 實例中,有一個叫做 news.* 的模式同時被客戶端client_789 和 client_999 訂閱,那么這個 redisServer 結(jié)構(gòu)看起來應(yīng)該是這樣子:
現(xiàn)在可以知道,實現(xiàn)PSUBSCRIBE命令的關(guān)鍵,就是將客戶端和訂閱的模式添加到redisServer.pubsub_patterns當(dāng)中。
新聞名稱:詳解Redis發(fā)布/訂閱模式
分享URL:http://m.fisionsoft.com.cn/article/dhcehdg.html


咨詢
建站咨詢
