Redis實現訊息佇列

公眾號程式設計師學長發表於2021-08-23

今天和大家來聊一聊Redis的Stream型別,Redis從5.0開始引入了一種新的資料型別Stream型別,它是專門為訊息佇列設計的資料型別。
首先,我們先來看一下訊息佇列存取訊息的過程。在分散式系統中,當兩個元件要基於訊息佇列進行通訊時,一個元件把訊息傳送到訊息佇列,我們稱之為生產者,另一個元件消費訊息,然後處理,我們稱之為消費者。如下圖所示:

   訊息佇列主要是解決生產者和消費者處理能力不一致的問題。也經常是大廠中必不可少的中介軟體。 Redis在5.0之前就有一個基於釋出訂閱(pub/sub)來實現訊息佇列的功能,但是,它有個缺點就是當出現網路斷開、Redis當機等,訊息就會被丟棄。而Redis Stream提供了訊息的持久化和主從複製功能,可以讓任何客戶端訪問任何時刻的資料,並且能記住每一個客戶端的訪問位置,還能保證訊息不丟失。
首先,我們看Redis Stream提供了哪些操作命令:

  • XADD 新增訊息到末尾
  • XTRIM 對流進行修剪,限制長度
  • XLEN 獲取流包含的元素數量,即訊息長度
  • XDEL 刪除訊息
  • XRANGE 獲取訊息列表,會自動過濾已經刪除的訊息
  • XREAD 以阻塞或非阻塞方式獲取訊息列表
  • XGROUP CREATE 建立消費組
  • XREADGROUP 按消費者的形式來讀取訊息
  • XACK 用於向訊息佇列確認訊息處理已完成
  • XPENDING 查詢每個消費組內所有消費者已讀取但尚未確認的訊息

一、常用命令

1. XADD

 XADD test * invent 5 
 1629701120782-0

  表示往名稱為test的訊息佇列中插入一條訊息,訊息的key是invent,值是5。其中test後面的“*”表示給插入的訊息自動生成一個全域性唯一的ID,1629701120782-0,前半部分1629701120782表示伺服器的時間,後半部分0表示插入訊息在當前毫秒內的訊息序號,從0開始。1629701120782-0表示1629701120782毫秒內的第一條訊息。

2. XTRIM

XTRIM test maxlen 100

 表示設定test的訊息佇列的長度為100,當Stream達到最大長度時,老的訊息就會被刪除。由於stream內部的實現機制,精確設定一個長度上限,消耗的資源會比較大,所以我們一般採用模糊設定的方式:XTRIM test maxlen ~ 100,意思是長度可以超過100一些,可以是103、110等,由redis自行判斷什麼時候去截斷。

3. XLEN

XLEN test

   表示獲取訊息佇列test的長度。

4. XDEL

XDEL test 1629701684031-0

   表示刪除訊息佇列test中,ID為1629701684031-0的訊息。

5. XRANGE

XRANGE test - +

   表示獲取test指定範圍內的訊息,其中“-”代表最小id,“+”代表最大id。

6. XREAD

XREAD block 10000 streams test $

   表示讀取訊息,其中“$”代表最新訊息,“block 10000”其中10000的單位是毫秒,代表10s。表示XREAD在讀取訊息時,如果沒有訊息到來,XREAD將阻塞10s,然後再返回。

7. XGROUP

XGROUP CREATE test mygroup 0

   表示給訊息佇列test建立一個消費組mygroup,0表示從最開始的位置讀。

8. XREADGROUP

XREADGROUP group mygroup consumer1 streams test >

   消費組mygroup中的消費者consumer1從訊息佇列test中讀取所有訊息,其中“>”表示從第一條尚未被消費的訊息開始讀取。
需要注意的是,訊息佇列中的訊息一旦被消費組裡的一個消費者消費了,就不能再被該消費組內的其他消費者讀取了。使用消費組的目的是讓組內的多個消費者共同分擔讀取訊息。所以,我們通常會讓每個消費者讀取部分訊息,從而實現訊息讀取負載在多個消費者間是均衡分佈的。

9. XPENDING

XPENDING test mygroup

   為了保證消費者在發生故障重啟後,仍然可以獲取到未處理完的訊息,Streams會自動使用內部佇列,來存放消費組裡每個消費者讀取的訊息,直到消費者使用XACK命令,通知Streams,訊息已處理完成。當消費者重啟後,可以使用XPENDING命令檢視已讀取,但是沒有被確認完成的訊息。

10. XACK

XACK test mygroup 1629701684031-0

   表示消費組mygroup已經確認處理了test訊息佇列中id為1629701684031-0的訊息。
到此為止,我們已經瞭解了使用Stream型別來實現訊息佇列的用法了。

二、總結

   你也許會想,我們為什麼要用Redis來做訊息佇列呢?要使用訊息佇列,就應該使用kafka、RabbitMQ這些專門的訊息佇列中介軟體,而Redis更適合做快取。其實,我認為,採用什麼技術和你當前所遇到的應用場景有關,如果你的訊息通訊不大,對資料丟失不敏感,那麼用redis作為訊息佇列不失為一個好的方法,畢竟redis相比kafka等專業的訊息系統來說,更加輕量級,維護成本也低。

   今天我們就聊到這裡,更多有趣知識,請關注【程式設計師學長】,回覆【資料】,可以獲得上百本技術類電子書,設計java、redis、python、資料結構和演算法等。 

   你知道的越多,你的思維也就越開闊,我們下期再見。

 

 

相關文章