一.場景介紹
最近的一個項目需要用到發布/訂閱的信息系統,以做到最新實時消息的通知。經查找后發現了redis pub/sub(發布/訂閱的信息系統)可以滿足我的開發需求,而且學習成本和使用成本也比較低。
二.什么是redis pub/sub
資料查看
大家在看我的blog的同時可以打開redis官方對於redis pub/sub的介紹,感覺看英文文檔吃力的話 :cry: ,可以看redis中文網的翻譯介紹.
Pub/Sub功能(means Publish, Subscribe)即發布及訂閱功能
- 基於事件的系統中,Pub/Sub是目前廣泛使用的通信模型,它采用事件作為基本的通信機制,提供大規模系統所要求的松散耦合的交互模式:訂閱者(如客戶端)以事件訂閱的方式表達出它有興趣接收的一個事件或一類事件;發布者(如服務器)可將訂閱者感興趣的事件隨時通知相關訂閱者。
- 消息發布者,即publish客戶端,無需獨占鏈接,你可以在publish消息的同時,使用同一個redis-client鏈接進行其他操作(例如:INCR等)
- 消息訂閱者,即subscribe客戶端,需要獨占鏈接,即進行subscribe期間,redis-client無法穿插其他操作,此時client以阻塞的方式等待“publish端”的消息;這一點很好理解,因此subscribe端需要使用單獨的鏈接,甚至需要在額外的線程中使用。
三.redis pub sub(publish subscribe)之基本使用
下面我將配着實圖(用我的本地機器環境)來為大家講解redis的pub/sub怎么去使用 .
沒有安裝phpredis擴展的或者沒有redis服務的,請參考我的 另一篇blog ,有詳細的安裝介紹,這里不再贅述了。
1、啟動redis服務端
2、啟動redis客戶端,並做為subscribe訂閱端
新開一個終端,啟動redis客戶端,並做為subscribe客戶端(消息訂閱者),訂閱一個名字叫test的頻道信息:
3、啟動redis客戶端,並做為publish客戶端
發布一個名字叫test的頻道,信息是:hello,world
4、查看訂閱到的消息
再切換到2步驟中的redis客戶端窗口,會發現,已經訂閱到了剛才發布的 'hello,world'消息:
其中,test為頻道名稱,hello,world即為消息
5、模式匹配訂閱
Redis 的Pub/Sub實現支持模式匹配。
客戶端可以訂閱全風格的模式以便接收所有來自能匹配到給定模式的頻道的消息。 比如,將接收所有發到 test.name,test.phone,test.address...等等的消息,該這樣寫:
PUBSCRIBE test.*
在終端回車后,同時再新的窗口里分別發布兩個頻道的消息,名字分別為:test.name和test.phone,然后切換到訂閱端的窗口里,結果如下圖所示:
由上圖可以看出,在訂閱了test.*頻道后,一共收到了 test.name和test.phone兩個頻道的消息,這就是模式匹配訂閱。
那么取消訂閱匹配該模式的客戶端也比較簡單:
PUNSUBSCRIBE test.*
好,以上的這些簡單的demo,就是關於redis pub/sub(Publish/Subscribe,發布/訂閱的信息系統)的最基本使用。說了這么多,跟php也沒有掛上什么鈎,別着急,重要的都往往最后出場。
四.php redis pub/sub
phpredis的安裝
redis的客戶端連接支持多種語言。這里我用的是php的phpredis,它是用c語言編寫的,目前已經作為php的一個模塊擴展,沒有安裝的可以參考我的 另一篇blog ,已經安裝的可以忽略此步驟.
命令手冊
詳細請看github 這里 。 這里我列出一些常用的:
Redis::__construct構造函數
$redis = new Redis(); connect, open 鏈接redis服務 參數 host: string,服務地址 port: int,端口號 timeout: float,鏈接時長 (可選, 默認為 0 ,不限鏈接時間) 注: 在redis.conf中也有時間,默認為300 pconnect, popen 不會主動關閉的鏈接 參考上面 setOption 設置redis模式 getOption 查看redis設置的模式 ping 查看連接狀態 get 得到某個key的值(string值) 如果該key不存在,return false set 寫入key 和 value(string值) 如果寫入成功,return ture setex 帶生存時間的寫入值 $redis->setex('key', 3600, 'value'); // sets key → value, with 1h TTL. setnx 判斷是否重復的,寫入值 $redis->setnx('key', 'value'); $redis->setnx('key', 'value'); delete 刪除指定key的值 返回已經刪除key的個數(長整數) $redis->delete('key1', 'key2'); $redis->delete(array('key3', 'key4', 'key5'));
更詳細的使用請參考這里 ,我就不寫太多,因為我要直接摞代碼了.
publish(消息發布端):pub.php
/** * redis sub(消息訂閱端) * @ blog: phping.sinaapp.com * @date 2016-04-24 15:00 */ $redis = new Redis(); // 第一個參數為redis服務器的ip,第二個為端口 $res = $redis->connect('127.0.0.1', 6379); // test為發布的頻道名稱,hello,world為發布的消息 $res = $redis->publish('test','hello,world');
subscribe(消息訂閱端): sub.php
/** * redis sub(消息訂閱端) * @ blog: phping.sinaapp.com * @date 2016-04-24 15:00 */ $redis = new Redis(); $res = $redis->pconnect('127.0.0.1', 6379,0); $redis->subscribe(array('test'), 'callback'); // 回調函數,這里寫處理邏輯 function callback($instance, $channelName, $message) { echo $channelName, "==>", $message,PHP_EOL; }
開始訂閱redis消息
前面已經提到過,消息訂閱者,即subscribe客戶端,需要獨占鏈接,即進行subscribe期間,redis-client無法穿插其他操作,此時client以阻塞的方式等待“publish端”的消息,所以我們用命令行來執行:
php啟動redis訂閱端
則 訂閱消息的redis客戶端已經啟動,隨時等待發布過來的消息並訂閱該消息. 發布redis消息 同樣,命令行執行消息發布端的腳本即可:
php pub.php
切換到消息訂閱端的窗口
發現終端有輸出,如下圖
哈哈,是不是 收到了發布端發布的'hello,world'這條消息呢。