Redis學習筆記(十)消息通知(任務隊列和發布訂閱模式)
1. 任務隊列
1.1 任務隊列的特點
任務隊列:顧名思義,就是“傳遞消息的隊列”。與任務隊列進行交互的實體有兩類,一類是生產者(producer),另一類則是消費者(consumer)。生產者將需要處理的任務放入任務隊列中,而消費者則不斷地從任務獨立中讀入任務信息並執行。
任務隊列的好處:
- 松耦合。生產者和消費者只需按照約定的任務描述格式,進行編寫代碼。
- 易於擴展。多消費者模式下,消費者可以分布在多個不同的服務器中,由此降低單台服務器的負載。
1.2 Redis實現任務隊列
使用Redis實現任務隊列首先想到的就是Redis的列表類型,因為在Redis內部,==列表類型是由雙向鏈表實現==的。
實現任務隊列,只需讓生產者將任務使用LPUSH加入到某個鍵中,然后另一個消費者不斷地使用RPOP命令從該鍵中取出任務即可。
//生產者只需將task LPUSH到隊列中 127.0.0.1:6379> LPUSH queue task (integer) 1 127.0.0.1:6379> LRANGE queue 0 -1 1) "task" //消費者只需從隊列中LPOP任務,如果為空則輪詢。 127.0.0.1:6379> LPOP queue "task"
BLPOP指令可以在隊列為空時處於阻塞狀態。就不用處於輪詢的狀態。
127.0.0.1:6379> BLPOP queue 0 //0表示無限制等待 //消費者當隊列為空則處於阻塞狀態。 //生產者將task LPUSH到隊列中,處於阻塞狀態的消費者離開返回 127.0.0.1:6379> LPUSH queue task (integer) 1 //消費者立刻“消費”,取出task。 127.0.0.1:6379> BLPOP queue 0 1) "queue" 2) "task" (13.38s)
1.3 優先級隊列
當一個隊列中有許多任務仍然沒有來得及被消費者及時消費時,如果出現緊急的消息,則不得不等待隊列中的任務被一一取出,因此,需要實現一個優先級隊列,當優先級隊列不為空時,消費者優先取出優先級隊列中的任務去執行。
BLPOP命令可以同時接收多個鍵BLPOP key [key ...] timeout
,當所有鍵(列表類型)都為空時,則阻塞,當其中一個有元素則會從該鍵返回。==如果多個鍵都有元素則按照從左到右的順序取第一個鍵中的一個元素,因此可以借此特性實現優先級隊列。==
127.0.0.1:6379> LPUSH queue1 first (integer) 1 127.0.0.1:6379> LPUSH queue2 second (integer) 1 //當兩個鍵都有元素時,按照從左到右的順序取第一個鍵中的一個元素 127.0.0.1:6379> BRPOP queue1 queue2 0 1) "queue1" 2) "first" 127.0.0.1:6379> BRPOP queue1 queue2 0 1) "queue2" 2) "second"
2. “發布/訂閱”模式
“發布/訂閱”(publish/subscribe)模式同樣可以實現進程間通信,==訂閱者可以訂閱一個或多個頻道(channel),而發布者可以向指定的頻道發送消息,所有訂閱次頻道的訂閱者都會收到次消息。==
2.1 命令實踐
- PUBLISH
- 將信息 message 發送到指定的頻道 channel。返回收到消息的客戶端數量。
- SUBSCRIBE
- 訂閱給指定頻道的信息。
- 一旦客戶端進入訂閱狀態,客戶端就只可接受訂閱相關的命令SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE和PUNSUBSCRIBE除了這些命令,其他命令一律失效。
- UNSUBSCRIBE
- 取消訂閱指定的頻道,如果不指定,則取消訂閱所有的頻道。
127.0.0.1:6379> PUBLISH channel1.1 test (integer) 0 //有0個客戶端收到消息 127.0.0.1:6379> SUBSCRIBE channel1.1 Reading messages... (press Ctrl-C to quit) 1) "subscribe" //"subscribe"表示訂閱成功的信息 2) "channel1.1" //表示訂閱成功的頻道 3) (integer) 1 //表示當前訂閱客戶端的數量 //當發布者發布消息時,訂閱者會收到如下消息 1) "message" //表示接收到消息 2) "channel1.1" //表示產生消息的頻道 3) "test" //表示消息的內容 //當訂閱者取消訂閱時會顯示如下: 127.0.0.1:6379> UNSUBSCRIBE channel1.1 1) "unsubscribe" //表示成功取消訂閱 2) "channel1.1" //表示取消訂閱的頻道 3) (integer) 0 //表示當前訂閱客戶端的數量 //注:在redis-cli中無法測試UNSUBSCRIBE命令
- 取消訂閱指定的頻道,如果不指定,則取消訂閱所有的頻道。
PSUBSCRIBE
- 訂閱給定的模式(patterns)。
PUNSUBSCRIBE
- 可以退訂指定的規則,如果沒有參數會退訂所有的規則。
127.0.0.1:6379> PSUBSCRIBE channel1.* Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "channel1.*" 3) (integer) 1 //等待發布者發布消息 127.0.0.1:6379> PUBLISH channel1.1 test1.1 (integer) 1 //發布者在channel1.1發布消息 1) "pmessage" //表示通過PSUBSCRIBE命令訂閱而收到的 2) "channel1.*" //表示訂閱時使用的通配符 3) "channel1.1" //表示收到消息的頻道 4) "test1.1" //表示消息內容 127.0.0.1:6379> PUBLISH channel1.2 test1.2 (integer) 1 //發布者在channel1.2發布消息 1) "pmessage" 2) "channel1.*" 3) "channel1.2" 4) "test1.2" 127.0.0.1:6379> PUBLISH channel1.3 test1.3 (integer) 1 //發布者在channel1.3發布消息 1) "pmessage" 2) "channel1.*" 3) "channel1.3" 4) "test1.3" 127.0.0.1:6379> PUNSUBSCRIBE channal1.* 1) "punsubscribe" //退訂成功 2) "channal1.*" //退訂規則的通配符 3) (integer) 0 //表示當前訂閱客戶端的數量
PUNSUBSCRIBE應該注意一下兩點:
-
-
- 使用PUNSUBSCRIBE命令只能退訂通過PSUBSCRIBE命令訂閱的規則,不會影響SUBSCRIBE訂閱的頻道。
- 使用PUNSUBSCRIBE命令退訂某個規則時不會將其中通配符展開,而是嚴格的進行==字符串匹配==,所以
PUNSUBSCRIBE *
無法退訂PUNSUBSCRIBE channal1.*
規則,而必須使用PUNSUBSCRIBE channal1.*
才能退訂
-