Redis發布與訂閱(pub/sub)
本文檔翻譯自: http://redis.io/topics/pubsub 。
SUBSCRIBE 、 UNSUBSCRIBE 和 PUBLISH 三個命令實現了發布與訂閱資訊泛型(Publish/Subscribe messaging paradigm), 在這個實現中, 寄件者(發送資訊的用戶端)不是將資訊直接發送給特定的接收者(接收資訊的用戶端), 而是將資訊發送給頻道(channel), 然後由頻道將資訊轉寄給所有對這個頻道感興趣的訂閱者。
寄件者無須知道任何關於訂閱者的資訊, 而訂閱者也無須知道是那個用戶端給它發送資訊, 它只要關注自己感興趣的頻道即可。
對發行者和訂閱者進行解構(decoupling), 可以極大地提高系統的擴充性(scalability), 並得到一個更動態網路拓撲(network topology)。
比如說, 要訂閱頻道 foo 和 bar , 用戶端可以使用頻道名字作為參數來調用 SUBSCRIBE 命令:
redis> SUBSCRIBE foo bar
當有用戶端發送資訊到這些頻道時, Redis 會將傳入的資訊推送到所有訂閱這些頻道的用戶端裡面。
正在訂閱頻道的用戶端不應該發送除 SUBSCRIBE 和 UNSUBSCRIBE 之外的其他命令。 其中, SUBSCRIBE 可以用於訂閱更多頻道, 而 UNSUBSCRIBE 則可以用於退訂已訂閱的一個或多個頻道。
SUBSCRIBE 和 UNSUBSCRIBE 的執行結果會以資訊的形式返回, 用戶端可以通過分析所接收資訊的第一個元素, 從而判斷所收到的內容是一條真正的資訊, 還是 SUBSCRIBE 或 UNSUBSCRIBE 命令的操作結果。 資訊的格式
頻道轉寄的每條資訊都是一條帶有三個元素的多條批量回複(multi-bulk reply)。
資訊的第一個元素標識了資訊的類型: subscribe : 表示當前用戶端成功地訂閱了資訊第二個元素所指示的頻道。 而資訊的第三個元素則記錄了目前用戶端已訂閱頻道的總數。 unsubscribe : 表示當前用戶端成功地退訂了資訊第二個元素所指示的頻道。 資訊的第三個元素記錄了用戶端目前仍在訂閱的頻道數量。 當客訂閱的頻道數量降為 0 時, 用戶端不再訂閱任何頻道, 它可以像往常一樣, 執行任何 Redis 命令。 message : 表示這條資訊是由某個用戶端執行 PUBLISH 命令所發送的, 真正的資訊。 資訊的第二個元素是資訊來源的頻道, 而第三個元素則是資訊的內容。
舉個例子, 如果用戶端執行以下命令:
redis> SUBSCRIBE first second
那麼它將收到以下回複:
1) "subscribe"2) "first"3) (integer) 11) "subscribe"2) "second"3) (integer) 2
如果在這時, 另一個用戶端執行以下 PUBLISH 命令:
redis> PUBLISH second Hello
那麼之前訂閱了 second 頻道的用戶端將收到以下資訊:
1) "message"2) "second"3) "hello"
當訂閱者決定退訂所有頻道時, 它可以執行一個無參數的 UNSUBSCRIBE 命令:
redis> UNSUBSCRIBE
這個命令將接到以下回複:
1) "unsubscribe"2) "second"3) (integer) 11) "unsubscribe"2) "first"3) (integer) 0
訂閱模式
Redis 的發布與訂閱實現支援模式比對(pattern matching): 用戶端可以訂閱一個帶 * 號的模式, 如果某個/某些頻道的名字和這個模式比對, 那麼當有資訊發送給這個/這些頻道的時候, 用戶端也會收到這個/這些頻道的資訊。
比如說,執行命令
redis> PSUBSCRIBE news.*
的用戶端將收到來自 news.art.figurative 、 news.music.jazz 等頻道的資訊。
客訂閱的模式裡面可以包含多個 glob 風格的萬用字元, 比如 * 、 ? 和 [...] , 等等。
執行命令
redis> PUNSUBSCRIBE news.*
將退訂 news.* 模式, 其他已訂閱的模式不會被影響。
通過訂閱模式接收到的資訊, 和通過訂閱頻道接收到的資訊, 這兩者的格式不太一樣: 通過訂閱模式而接收到的資訊的類型為 pmessage : 這代表有某個用戶端通過 PUBLISH 向某個頻道發送了資訊, 而這個頻道剛好匹配了當前用戶端所訂閱的某個模式。 資訊的第二個元素記錄了被匹配的模式, 第三個元素記錄了被匹配的頻道的名字, 最後一個元素則記錄了資訊的實際內容。
用戶端處理 PSUBSCRIBE 和 PUNSUBSCRIBE 傳回值的方式, 和用戶端處理 SUBSCRIBE 和 UNSUBSCRIBE 的方式類似: 通過對資訊的第一個元素進行分析, 用戶端可以判斷接收到的資訊是一個真正的資訊, 還是 PSUBSCRIBE 或 PUNSUBSCRIBE 命令的傳回值。 通過頻道和模式接收同一條資訊
如果客訂閱的多個模式比對了同一個頻道, 或者用戶端同時訂閱了某個頻道、以及匹配這個頻道的某個模式, 那麼它可能會多次接收到同一條資訊。
舉個例子, 如果用戶端執行了以下命令:
SUBSCRIBE fooPSUBSCRIBE f*
那麼當有資訊發送到頻道 foo 時, 用戶端將收到兩條資訊: 一條來自頻道 foo ,資訊類型為 message ; 另一條來自模式 f* ,資訊類型為 pmessage 。 訂閱總數
在執行 SUBSCRIBE 、 UNSUBSCRIBE 、 PSUBSCRIBE 和 PUNSUBSCRIBE 命令時, 返回結果的最後一個元素是用戶端目前仍在訂閱的頻道和模式總數。
當用戶端退訂所有頻道和模式, 也即是這個總數值下降為 0 的時候, 用戶端將退出訂閱與發布狀態。 編程樣本
Pieter Noordhuis 提供了一個使用 EventMachine 和 Redis 編寫的 高效能多使用者網頁聊天軟體 , 這個軟體很好地展示了發布與訂閱功能的用法。 用戶端庫實現提示
因為所有接收到的資訊都會包含一個資訊來源: 當資訊來自頻道時,來源是某個頻道; 當資訊來自模式時,來源是某個模式。
因此, 用戶端可以用一個雜湊表, 將特定來源和處理該來源的回呼函數關聯起來。 當有新資訊到達時, 程式就可以根據資訊的來源, 在 O(1) 複雜度內, 將資訊交給正確的回呼函數來處理。
from: http://redisdoc.com/topic/pubsub.html