Redis實現消息隊列

今天和大家來聊一聊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、數據結構和演算法等。 

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

 

 

Tags: