Python–Redis實戰:第三章:Redis命令:第六節:釋出與訂閱

Mark發表於2019-02-16

上一篇文章:Python–Redis實戰:第三章:Redis命令:第五節:有序集合
下一篇文章:Python–Redis實戰:第三章:Redis命令:第七節:其他命令

一般來說,釋出於訂閱(又稱pub/sub)的特點是訂閱者(listener)負責訂閱頻道(channel),傳送者(publisher)負責向頻道傳送二進位制字串訊息(binary string message)。每當有訊息被髮送至給定頻道時,頻道的所有訂閱者都會收到訊息。我們也可以把頻道看作是電臺,其中訂閱者可以同時收聽多個電臺,而傳送者則可以在任何電臺傳送資訊。

本節將對釋出與訂閱的相關操作進行介紹,閱讀這一節可以讓讀者學會怎樣使用釋出與訂閱的相關命令,並瞭解到為什麼本書在之後的章節裡面會使用其他相似的解決方案來代替Redis提供的釋出與訂閱。

下表展示了Redis提供的5個釋出與訂閱命令:

命令 用例 用例描述
subscribe subscribe channel [channel …] 訂閱給定的一個或多個頻道
unsubscribe unsubscribe [channnel channel …] 退訂給定的一個或多個頻道,如果執行時沒有給定任何頻道,那麼退訂所有頻道
publish publish channel message 向給定頻道傳送訊息
psubscribe psubscribe pattern [pattern …] 訂閱與給定模式相匹配的所有頻道
punsunscribe punsunscribe [pattern [pattern …]] 退訂給定的模式,如果執行時沒有給定任何模式,那麼退訂所有模式。

考慮到publish命令和subscribe命令在Python客戶端的實現方式,一個比較簡單的演示釋出與訂閱的方法,就像下面程式碼清單那樣使用輔助執行緒(helper thread)來執行publish命令:

import redis  # 匯入redis包包
import time,threading


# 與本地redis進行連結,地址為:localhost,埠號為6379

r = redis.StrictRedis(host=`localhost`, port=6379)

def publisher(n):
    #函式在開始執行時會先休眠,讓訂閱者有足夠的事件來連線伺服器並監聽訊息
    time.sleep(1)
    for i in range(n):
        r.publish(`channel`,i)
        #在傳送訊息之後進行短暫的休眠,讓訊息可以一條接一條地出現
        time.sleep(1)

def run_pubsub():
    #啟動傳送者執行緒,並讓它傳送三條訊息
    threading.Thread(target=publisher,args=(3,)).start()
    #建立釋出於訂閱物件,並對它訂閱給定的頻道
    pubsub=r.pubsub()
    pubsub.subscribe([`channel`])
    count=0
    #通過遍歷函式pubsub.listen()的執行結果來監聽訂閱訊息
    for item in pubsub.listen():
        #列印接收到的每條訊息
        print(item)
        count+=1
        if count==4:
            pubsub.unsubscribe()
        if count==5:
            break

if __name__ == `__main__`:
    run_pubsub()

執行結果:

{`type`: `subscribe`, `pattern`: None, `channel`: b`channel`, `data`: 1}
{`type`: `message`, `pattern`: None, `channel`: b`channel`, `data`: b`0`}
{`type`: `message`, `pattern`: None, `channel`: b`channel`, `data`: b`1`}
{`type`: `message`, `pattern`: None, `channel`: b`channel`, `data`: b`2`}
{`type`: `unsubscribe`, `pattern`: None, `channel`: b`channel`, `data`: 0}

在剛開始訂閱一個頻道的時候,客戶端會接收到一條關於被訂閱頻道的反饋。

在退訂頻道時,客戶端會接受到一條反饋資訊,告知被退訂的是哪個頻道,以及客戶端目前仍在訂閱的頻道數量。

雖然Redis的釋出與訂閱非常有用,但本書只在這一節和8.5節使用了這個模式,這樣做的原因主要有以下兩個:

  • 第一個原因和Redis系統的穩定性有關。對於舊版Redis來說,如果一個客戶端訂閱了某個或某些頻道,但它讀取訊息的速度卻不夠快的話,那麼不斷積壓的訊息會使得Redis輸出緩衝區的體積變得越來越大,這可能會導致Redis的速度變慢,甚至直接崩潰。也可能會導致Redis被作業系統強制殺死,甚至導致作業系統本身不可用。新版的Redis不會出現這種問題,因為它會自動斷開不符合client-output-buffer-limit pubsub配置選項要求的訂閱客戶端。
  • 第二個原因和資料傳輸的可靠性有關。任何網路系統在執行操作時都可能會遇到斷線情況,而斷線產生的連線錯誤通常會使得網路連線兩端的其中一端進行重新連線。本書使用的Python語言的Redis客戶端會在連線失效時自動程式重新連線,也會自動處理連線池(connection pool),諸如此類。但是,如果客戶端在執行訂閱操作的過程中斷線,那麼客戶端將丟失在斷線期間傳送的所有訊息,因此依靠頻道來接受訊息的使用者可能會對Redis提供的publish命令和subscribe命令的語義感到失望。

基於以上兩個原因,本書在第六章編寫了兩個不同的方法來實現可靠的訊息傳遞操作,這兩個方法除了可以處理網路斷線之外,還可以防止Redis因為訊息擠壓而耗費過多記憶體(這個方法即使對於舊版的Redis也是有效的)。

如果你喜歡簡單易用的publish命令和subscribe命令,並且能夠承擔可能會丟失一小部分資料的風險,那麼你也可以繼續使用Redis提供的釋出與訂閱特性,而不是8.5節中提供的實現,只要記得先把client-output-buffer-limit pubsub選項設定好就行了。

到目前為止,本書介紹的大多數命令都是與特定資料型別相關的。接下來的一節要介紹的命令你可能也會用到,但它們既不屬於Redis提供的5中資料結構,也不屬於釋出與訂閱特性。

上一篇文章:Python–Redis實戰:第三章:Redis命令:第五節:有序集合
下一篇文章:Python–Redis實戰:第三章:Redis命令:第七節:其他命令

相關文章