天天看點

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

消息隊列つ登場

大家好,我是老三,是一個電商公司的程式員,負責訂單系統的開發。

掉了不少頭發之後,我完成了使用者訂單支付的開發。

訂單支付的業務是這樣的。使用者支付完成之後,我需要更新訂單狀态,這一部分是在本系統完成的。接下來,我要調用庫存系統,減庫存,好了,剩下的就是庫存系統的事情了。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

開發、聯調、測試、上線,我的小日子變得清閑起來,每天就是在群裡吹牛打屁。

可是沒過兩天,産品妹子,找過來了,她說,她想加個功能,使用者完成訂單支付以後,要增加使用者的積分。

沒問題,so easy,噼裡啪啦,我兩天就做完了,無非是調用一下會員系統。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

這天,正和沙雕群友鬥圖的時候,産品妹子過來,他說要接入消息系統,好,搞!

又過兩天,她說要添加營銷系統,行吧,幹!

又過兩天,她說要搞推薦系統,嗯……,來吧!

又過兩天……

于是系統就變成了這個樣子:

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

就這樣,我過上了暗無天日的日子,我要維護和若幹個系統的對接,每次他們釋出新版本,我都要跟着值班。

我要疊代,也要改和幾個系統的對接代碼。

周一,營銷系統;

周二,庫存系統;

……

這天,眼圈發黑的我正在和下遊服務撕巴的時候,突然忍不住兩腿戰戰,她來了,産品妹(女)子(王)來了——她是我不能拒絕的女人。

脆弱的眼淚流了滿面,我的猿生一片灰暗……

沒想到,代救星出現了,我的好朋友傲天過來了,拿鼻孔看着我。

“你個Loser,竟不知道用消息隊列,怪不得天天被人欺負,哼!”

一語驚醒夢中人,為什麼不用消息隊列啊?

于是我引入消息隊列,對系統進行了重構。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

這下好了,我隻管

更新訂單狀态

,剩下的丢給消息隊列,你們這些下遊自己去消息隊列消費消息就好了,别來纏着我了。

引入消息隊列之後,又是一個閑适的下午。

我沒有在群聊裡扯扯,因為我退群了。

前幾天,我受到了前所未有的傷害——

我在群裡嘲諷一個老哥,技術真菜,連消息隊列都不會!

老哥反手就發出他和女朋友的合照,“單身狗,技術好又怎麼樣,連個女朋友都沒有!”

我瞬間san值狂掉!

“程式員單身,不算單身……new個對象的事,能算單身麼?”接連着便是什麼難懂的話,什麼“沒有妹子”,什麼“哲學”之類,引得衆人都哄笑起來,群裡充滿了快活的空氣。

于是,這個下午我盯着空空如也的需求單發呆,公司真的沒有妹子麼?……

好了,冗長的前奏結束了,接下來該進入正文了😂。

消息隊列つ用途

在上面的前言中,我們已經了解了消息隊列最重要的一個用途:

  • 解耦

通過消息隊列,降低系統間的耦合,避免過多的調用。

就好像公司的行政小姐姐要通知一件事情,她通常會是在群裡發一個公告,然後我們扣1就行了。要是一個個通知,她要通知幾十上百次。

  • 異步

還是上面我們提到的訂單支付,支付之後,我們要扣減庫存、增加積分、發送消息等等,這樣一來這個鍊路就長了,鍊路一長,響應時間就變長了。引入消息隊列,除了

更新訂單狀态

,其它的都可以異步去做,這樣一來就來,就能更快地響應我們的上遊。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

為什麼不用多線程之類的方式做異步呢?——

嗨,隻用多線程做異步,不是還得寫代碼去調那一堆下遊嗎,是以這又回到了解耦這個問題上。

  • 削峰

消息隊列同樣可以用來削峰。

用一個比喻,一條河流,假如它的下遊能容納的水量是有限的,為了防止洪水沖垮堤壩,我們應該怎麼辦呢?

我們可以在上遊修建一個水庫,洪峰來的時候,我們先把水給蓄起來,閘口裡隻放出下遊能承受地住的水量。

放在我們的系統,也是一個道理。比如秒殺系統,平時流量很低,但是要做秒殺活動,秒殺的時候流量瘋狂怼進來,你的伺服器,Redis,MySQL各自的承受能力都不一樣,直接全部流量照單全收肯定有問題啊,嚴重點可能直接打挂了。

是以一樣,我們可以把請求放到隊列裡面,隻放出我們下遊服務能處理的流量,這樣就能抗住短時間的大流量了。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

除了這三大用途之外,還可以利用隊列本身的順序性,來滿足消息必須按順序投遞的場景;利用隊列 + 定時任務來實作消息的延時消費 ……

消息隊列つ本質

過氣老北鼻馬老師有三招——

消息隊列核心有三闆斧:

消費

生産者先将消息投遞一個叫做「隊列」的容器中,然後再從這個容器中取出消息,最後再轉發給消費者[1]。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

上面這個圖便是消息隊列最原始的模型,它包含了消息隊列中的一兩個關鍵詞

消息

和隊列

隊列

  1. 消息:就是要傳輸的資料,可以是最簡單的文本字元串,也可以是自定義的複雜格式。
  2. 隊列:大家應該再熟悉不過了,是一種先進先出資料結構。它是存放消息的容器,消息從隊尾入隊,從隊頭出隊,入隊即發消息的過程,出隊即收消息的過程。

是以消息隊列的本質就是把要傳輸的資料放在隊列中。

圍繞着這個本質:

  • 把資料放到消息隊列的角色就是

    生産者

  • 把資料從隊列中取出的就是

    消費者

消息隊列つ模型

[1]我們上面已經了解了消息隊列模型的本質,随着應用場景的變化,消息隊列的模型逐漸發生了一些演進。

就好像我們的文字通訊,最開始單對單地發消息,後來可以群發,再後來,可以拉一個群聊。

  • 隊列模型

最初的消息隊列就是上一節講的原始模型,它是一個嚴格意義上的隊列(Queue)。消息按照什麼順序寫進去,就按照什麼順序讀出來。不過,隊列沒有 “讀” 這個操作,讀就是出隊,從隊頭中 “删除” 這個消息。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

如果有多個生産者往同一個隊列裡面發送消息,這個隊列中可以消費到的消息,就是這些生産者生産的所有消息的合集。消息的順序就是這些生産者發送消息的自然順序。

如果有多個消費者接收同一個隊列的消息,這些消費者之間實際上是競争的關系,每個消費者隻能收到隊列中的一部分消息,也就是說任何一條消息隻能被其中的一個消費者收到。

  • 釋出 - 訂閱模型

如果需要将一份消息資料分發給多個消費者,并且每個消費者都要求收到全量的消息。很顯然,隊列模型無法滿足這個需求。

一個可行的方案是:為每個消費者建立一個單獨的隊列,讓生産者發送多份。這種做法比較笨,而且同一份資料會被複制多份,也很浪費空間。

為了解決這個問題,就演化出了另外一種消息模型:釋出-訂閱模型。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

在釋出 - 訂閱模型中,消息的發送方稱為釋出者(Publisher),消息的接收方稱為訂閱者(Subscriber),服務端存放消息的容器稱為主題(Topic)。釋出者将消息發送到主題中,訂閱者在接收消息之前需要先“訂閱主題”。“訂閱”在這裡既是一個動作,同時還可以認為是主題在消費時的一個邏輯副本,每份訂閱中,訂閱者都可以接收到主題的所有消息。

仔細對比下它和 “隊列模式” 的異同:生産者就是釋出者,隊列就是主題,消費者就是訂閱者,無本質差別。唯一的不同點在于:一份消息資料是否可以被多次消費。

消息隊列つ代價

天下沒有白吃的午餐——這句話放在系統設計中同樣适用。引入了消息隊列,解決了一些問題,但同時也增加了系統的複雜性和維護成本。[5]

  • 高可用

前面說,我們引入了消息隊列,降低了系統間的耦合,但是,我們對消息隊列的依賴也變重了,想想,要是消息隊列挂了,那我們下遊就全涼了。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

是以,我們消息隊列的部署必須保證高可用,至少是

主/從

,一般都得

叢集/分布式

  • 消息丢失問題

我們将資料寫到消息隊列上,下遊服務沒來得及取消息隊列的資料,突然挂了。如果沒有做任何的措施,我們的資料就丢了。

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

那可怎麼辦呢?

消息隊列中的資料得想辦法存在别的地方,這樣才盡可能減少資料的丢失。

問題又來了,存在哪呢?

  • 磁盤?
  • 資料庫?
  • Redis?
  • 分布式檔案系統?

同步存儲還是異步存儲?

  • 重複消費問題

要是我們網絡延遲或者什麼原因,導緻下遊重複消費怎麼辦?

我們這個問題是在消息隊列解決?還是在下遊服務解決?

還有其它的順序消息等等問題。

這些問題都是選型時候需要充分考慮的。

消息隊列つ選擇

目前在市面上比較主流的主要有四大消息中間件:Kafka、ActiveMQ、RabbitMQ、RocketMQ 。

它們的對比我整理了一張圖:

十二張圖,踹開消息隊列的大門消息隊列つ登場消息隊列つ用途消息隊列つ本質消息隊列つ模型消息隊列つ代價消息隊列つ選擇消息隊列つ終焉

消息隊列つ終焉

好了,到這我們就了解了消息隊列的一些基礎的知識。

門外漢,這個門,你入了嗎?我反正是在裡面打滾了。

“簡單的事情重複做,重複的事情認真做,認真的事情有創造性地做!”——

我是三分惡,一個能文能武的全棧開發。

點贊

關注

不迷路,咱們下期見!

繼續閱讀