美團面試:Redis 除了緩存還能做什麼?可以做消息隊列嗎?

這是一道面試中常見的 Redis 基礎面試題,主要考察求職者對於 Redis 應用場景的瞭解。

即使不準備面試也建議看看,實際開發中也能夠用到。

內容概覽:

Redis 除了做緩存,還能做什麼?

  • 分佈式鎖:通過 Redis 來做分佈式鎖是一種比較常見的方式。通常情況下,我們都是基於 Redisson 來實現分佈式鎖。關於 Redis 實現分佈式鎖的詳細介紹,可以看我寫的這篇文章:如何基於 Redis 實現分佈式鎖?
  • 限流:一般是通過 Redis + Lua 腳本的方式來實現限流。相關閱讀:《我司用了 6 年的 Redis 分佈式限流器,可以說是非常厲害了!》
  • 消息隊列:Redis 自帶的 List 數據結構可以作爲一個簡單的隊列使用。Redis 5.0 中增加的 Stream 類型的數據結構更加適合用來做消息隊列。它比較類似於 Kafka,有主題和消費組的概念,支持消息持久化以及 ACK 機制。
  • 延時隊列:Redisson 內置了延時隊列(基於 Sorted Set 實現的)。
  • 分佈式 Session :利用 String 或者 Hash 數據類型保存 Session 數據,所有的服務器都可以訪問。
  • 複雜業務場景:通過 Redis 以及 Redis 擴展(比如 Redisson)提供的數據結構,我們可以很方便地完成很多複雜的業務場景比如通過 Bitmap 統計活躍用戶、通過 Sorted Set 維護排行榜。
  • ……

如何基於 Redis 實現分佈式鎖?

關於 Redis 實現分佈式鎖的詳細介紹,可以看我寫的這篇文章:如何基於 Redis 實現分佈式鎖?

Redis 可以做消息隊列麼?

實際項目中也沒見誰使用 Redis 來做消息隊列,對於這部分知識點大家瞭解就好了。

先說結論:可以是可以,但不建議使用 Redis 來做消息隊列。和專業的消息隊列相比,還是有很多欠缺的地方。

Redis 2.0 之前,如果想要使用 Redis 來做消息隊列的話,只能通過 List 來實現。

通過 RPUSH/LPOP 或者 LPUSH/RPOP即可實現簡易版消息隊列:

# 生產者生產消息
> RPUSH myList msg1 msg2
(integer) 2
> RPUSH myList msg3
(integer) 3
# 消費者消費消息
> LPOP myList
"msg1"

不過,通過 RPUSH/LPOP 或者 LPUSH/RPOP這樣的方式存在性能問題,我們需要不斷輪詢去調用 RPOPLPOP 來消費消息。當 List 爲空時,大部分的輪詢的請求都是無效請求,這種方式大量浪費了系統資源。

因此,Redis 還提供了 BLPOPBRPOP 這種阻塞式讀取的命令(帶 B-Bloking 的都是阻塞式),並且還支持一個超時參數。如果 List 爲空,Redis 服務端不會立刻返回結果,它會等待 List 中有新數據後在返回或者是等待最多一個超時時間後返回空。如果將超時時間設置爲 0 時,即可無限等待,直到彈出消息

# 超時時間爲 10s
# 如果有數據立刻返回,否則最多等待10秒
> BRPOP myList 10
null

List 實現消息隊列功能太簡單,像消息確認機制等功能還需要我們自己實現,最要命的是沒有廣播機制,消息也只能被消費一次。

Redis 2.0 引入了發佈訂閱 (pub/sub) 功能,解決了 List 實現消息隊列沒有廣播機制的問題。

Redis 發佈訂閱 (pub/sub) 功能

pub/sub 中引入了一個概念叫 channel(頻道),發佈訂閱機制的實現就是基於這個 channel 來做的。

pub/sub 涉及發佈者(Publisher)和訂閱者(Subscriber,也叫消費者)兩個角色:

  • 發佈者通過 PUBLISH 投遞消息給指定 channel。
  • 訂閱者通過SUBSCRIBE訂閱它關心的 channel。並且,訂閱者可以訂閱一個或者多個 channel。

我們這裏啓動 3 個 Redis 客戶端來簡單演示一下:

pub/sub 實現消息隊列演示

pub/sub 既能單播又能廣播,還支持 channel 的簡單正則匹配。不過,消息丟失(客戶端斷開連接或者 Redis 宕機都會導致消息丟失)、消息堆積(發佈者發佈消息的時候不會管消費者的具體消費能力如何)等問題依然沒有一個比較好的解決辦法。

爲此,Redis 5.0 新增加的一個數據結構 Stream 來做消息隊列。Stream 支持:

  • 發佈 / 訂閱模式
  • 按照消費者組進行消費
  • 消息持久化( RDB 和 AOF)

Stream 使用起來相對要麻煩一些,這裏就不演示了。而且,Stream 在實際使用中依然會有一些小問題不太好解決比如在 Redis 發生故障恢復後不能保證消息至少被消費一次。

綜上,和專業的消息隊列相比,使用 Redis 來實現消息隊列還是有很多欠缺的地方比如消息丟失和堆積問題不好解決。因此,我們通常建議不要使用 Redis 來做消息隊列,你完全可以選擇市面上比較成熟的一些消息隊列比如 RocketMQ、Kafka。

相關閱讀:Redis 消息隊列發展歷程 - 阿里開發者 - 2022

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章