消息隊列:Stream

問題1:Stream工作過程如何?

答:Stream有一個消息鏈表,將所有加入的消息都串起來,每個消息都有一個唯一的ID和對應的內容。消息是持久化的,Redis重啓後內容還在。

每個Stream都有唯一的名稱,名稱就是Redis的key,在首次使用xadd指令追加消息時自動創建

每個Stream都可以掛多個消費組,每個消費組會有個遊標last_delivered_id在Stream 數組之上往前移動,表示當前消費組已經消費到哪條消息了。每個消費組都有一個Stream內唯一的名稱,消費組不會自動創建,它需要單獨的指令xgroup create進行創建,需要指定從Stream的某個消息ID開始消費,這個ID用來初始化last_delivered_id變量。

每個消費組的狀態都是獨立的,相互不受影響。也就是說同一 Stream內部的消息會被每個消費組都消費到。

同一個消費組可以掛接多個消費者,這些消費者之間是競爭關係,任意一個消費者讀取了消息都會使遊標last_delivered_id往前移動。每個消費者有一個組內唯一名稱。

消費者內部會有個狀態變量pending_ids,它記錄了當前已經被客戶端讀取的消息,但是還沒有ack。如果客戶端沒有ack,這個變量裏面的消息ID會越來越多,一旦某個消息被ack,它就開始減少。這個pending_ids變量被稱之爲PEL,也就是Pending Entries List。

問題2:消息ID格式是什麼?

答:timestampInMillis-sequence。可以由服務器自動生成,也可以由客戶端自己指定,但是形式必須是整數-整數,而且必須是後面加入的消息的ID要大於前面的消息ID。

問題3:消息內容格式是什麼?

答:鍵值對形式。

問題4:指令有哪些?

答:

xadd追加消息

xdel刪除消息,這裏的刪除僅僅是設置了標誌位,不影響消息總長度

xrange獲取消息列表,會自動過濾已經刪除的消息

xlen消息長度

del刪除 Stream

xgroup create指令創建消費組,需要傳遞起始消息ID參數用來初始化last_delivered_id變量。

xreadgroup指令可以進行消費組的組內消費,需要提供消費組名稱、消費者名稱和起始消息ID。它同xread一樣,也可以阻塞等待新消息。讀到新消息後,對應的消息 ID 就會進入消費者的 PEL結構裏,客戶端處理完畢後使用xack指令通知服務器,本條消息已經處理完畢,該消息 ID 就會從PEL中移除。

問題5:xread指令有何特別之處?

答:xread可以將Stream當做一個普通的列表list,該Stream所有的消費組全部忽略不見。

Xread會返回消息ID,下次繼續調用xread 時,將上次返回的最後一個消息ID作爲參數傳遞進去,就可以繼續消費後續的消息。

問題6:Stream消息太多如何處理?

答:Redis提供了一個定長Stream功能。在xadd指令提供一個定長長度maxlen,就可以將老的消息幹掉,確保最多不超過指定長度。

問題7:如果客戶端忘記ACK,會造成什麼後果?

答:如果消費者收到了消息處理完了但是沒有回覆ack,就會導致PEL列表不斷增長,進而導致PEL佔用的內存就會放大。

問題8:消費者如何確保客戶端收到消息?

答:客戶端斷開連接又重新連上之後,可以再次收到PEL中的消息ID列表。不過此時xreadgroup的起始消息ID不能爲參數,而必須是任意有效的消息ID,一般將參數設爲 0-0來表示讀取所有的 PEL消息以及自last_delivered_id之後的新消息。

問題9:Stream如何實現高可用?

答:Stream高可用是建立主從複製基礎上的,也就是說在 Sentinel和 Cluster集羣環境下Stream是可以支持高可用的。鑑於 Redis指令複製是異步的,在failover發生時Redis可能會丟失極小部分數據,這點Redis的其它數據結構也是一樣的。

發佈了167 篇原創文章 · 獲贊 10 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章